Codeforces 853 D. Michael and Charging Stations —— 一眼DP

This way

题意:

你每天会花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
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;
}

你可能感兴趣的:(dp)