https://vjudge.net/problem/HRBUST-2455
有两种优惠方式,一是满400减100,另外一种是商品自带折扣,二者不可叠加
dp[i][j]表示前i种商品,(参与满400减100活动的商品价格之和)%400 == j 的最少总花费,这里默认后面的商品都使用自身折扣,
为了避免小数,把价格A[i]都扩大十倍A[i]*=10。
容易得到转移方程 dp[i][j] = min(dp[i-1][x]+j*10+(x+A[i]/10)/400*3000-x*10-A[i]/10*B[i],dp[i-1][j])
其中 x = (j-A[i]+1200)%400
边界dp[0][0]表示所有商品只使用自身折扣
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; #define int long long int t; int N; int A[1003]; int B[1003]; int dp[1004][400]; double ans =0.0; const int INF = 1e18; signed main() { scanf("%lld",&t); while(t--){ int tmp =0; scanf("%lld",&N); for(int i=1;i<=N;i++){ scanf("%lld%lld",&A[i],&B[i]); tmp+=A[i]*B[i]; A[i]*=10; for(int j=0;j<400;j++){ dp[0][j]=dp[i][j]=INF; } } dp[0][0]=tmp; int x ; for(int i=1;i<=N;i++){ for(int j=0;j<400;j++){ x= (j-A[i]/10+1200)%400; dp[i][j]=min(dp[i-1][x]-(A[i]/10ll)*B[i]+j*10ll-x*10ll+((x+A[i]/10ll)/400ll)*3000ll,dp[i-1][j]); } } tmp = 1e18; for(int j=0;j<400;j++){ tmp = min(tmp,dp[N][j]); } printf("%.1f ",tmp*0.1); } }