题意:
你每天会花a[i]块钱去买东西,a[i]=2000|a[i]=1000.如果你这次支付全用现金,那么你会获得
a
[
i
]
/
10
a[i]/10
a[i]/10块钱信用金,或者你可以信用金和现金混用,这样不会获得信用金。问你n天最少要花多少钱。
题解:
首先考虑DP
dp[i][j]表示到了第i天,身上有j元信用金时的最小花费。那么有两种转移:
dp[i][j]->dp[i+1][j+a[i]/10]
dp[i][j]->dp[i+1][max(0,j-a[i])]
我们知道信用金如果在这一轮用了,那么用的尽可能多更好,因为反正你获得不了奖金了,拖到后面可能还会赘余。
所以j这一维开4000左右就够了(当然我开了10000以防万一)
这时候会发现空间复杂度太大了
然后又发现,百位以下是没用的,那么我们直接将a[i]/100,然后进行计算,最后再乘上100
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int a[N],dp[N][105];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),a[i]/=100;
memset(dp,-1,sizeof(dp));
dp[1][0]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=100;j++){
if(~dp[i][j]){
if(~dp[i+1][j+a[i]/10])
dp[i+1][j+a[i]/10]=min(dp[i+1][j+a[i]/10],dp[i][j]+a[i]);
else
dp[i+1][j+a[i]/10]=dp[i][j]+a[i];
int use=min(j,a[i]);
if(~dp[i+1][j-use])
dp[i+1][j-use]=min(dp[i+1][j-use],dp[i][j]+a[i]-use);
else
dp[i+1][j-use]=dp[i][j]+a[i]-use;
}
}
}
int ans=1e9;
for(int i=0;i<=100;i++)
if(~dp[n+1][i])
ans=min(ans,dp[n+1][i]*100);
printf("%d\n",ans);
return 0;
}