cf 853 D Michael and Charging Stations [dp]

题面:

传送门

思路:

看到题目,第一思路是贪心,但是我很快就否决掉了(其实分类贪心也可以做)

然后就想,贪心不能解决的状态缺失,是否可以用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 }
原文地址:https://www.cnblogs.com/dedicatus545/p/8453821.html