题面:
思路:
看到题目,第一思路是贪心,但是我很快就否决掉了(其实分类贪心也可以做)
然后就想,贪心不能解决的状态缺失,是否可以用dp来解决呢?
事实证明是可以的
我们设dp[i][j]表示第i天,还剩j*100积分的时候,最小花费的现金
有转移:dp[i][j]=min(dp[i-1][k]+cost[i]-(k-j)*100)(k=j+1...min(30,j+cost[i]/100)
最后再dp[i][j]=min(dp[i][j],dp[i-1][j-cost[i]/1000]+cost[i])
这里k的上限是30是因为最多攒3000积分以后就必须要花掉,不然也不会更加划算(支付1000+2000)(证明太长了......)
Code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define inf 1e9 6 using namespace std; 7 inline int read(){ 8 int re=0,flag=1;char ch=getchar(); 9 while(ch>'9'||ch<'0'){ 10 if(ch=='-') flag=-1; 11 ch=getchar(); 12 } 13 while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar(); 14 return re*flag; 15 } 16 int n,a[300010]; 17 int dp[300010][31]; 18 int main(){ 19 int i,j,k,ans=inf; 20 n=read(); 21 for(i=1;i<=n;i++) a[i]=read(); 22 for(i=1;i<=30;i++) dp[0][i]=inf; 23 for(i=1;i<=n;i++){ 24 for(j=0;j<=30;j++){ 25 dp[i][j]=inf; 26 for(k=min(30,j+a[i]/100);k>j;k--){ 27 dp[i][j]=min(dp[i][j],dp[i-1][k]+a[i]-(k-j)*100); 28 } 29 if(j>=a[i]/1000) dp[i][j]=min(dp[i][j],dp[i-1][j-a[i]/1000]+a[i]); 30 // cout<<i<<ends<<j<<ends<<dp[i][j]<<endl; 31 } 32 } 33 for(i=0;i<=30;i++) ans=min(ans,dp[n][i]); 34 printf("%d ",ans); 35 }