codeforces730F - Ber Patio

題面在這裏

題意:

你要按順序買n 個物品,每個物品的花費分別爲a1...an 。初始時有一張價值爲b 的代金券。

每次最多可以使用min(ai2,b) 元的代金券,此時如果消費x元,則能得到x/10 元新的代金券。

問需要花費的最少代價。

n<=5000,ai<=1000,ai<=105,b<=105

做法:

感覺這題dp的做法還是挺好理解的吧。

f[i][j] 表示前i天得到了j元的代金券所用的最少錢數。

sum[i] 表示a[i] 的前綴和,則第i天能用的代金券錢數就等於b(sum[i]f[i][j])+j

轉移的時候直接枚舉花多少代金券即可,然後由於要輸出方案就記錄一個pre 數組保存最優方案。

然後這樣複雜度看起來有點大qwq。

考慮 i 和 k 的循環時間複雜度爲 ai25×104jai10104 ,因此整個時間複雜度是 O((ai)220) ,最壞情況計算次數5×108 。由於時限 3s ,因此是可以過的(事實上最慢的點跑了還不到 1shhhh)。

——摘自這裏

然而我發現我的程序總共只跑了200+ms。

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cctype>
using namespace std;
typedef long long ll;

inline ll read() {
    char ch = getchar(); ll x = 0; int op = 1;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
    for(; isdigit(ch); ch = getchar()) x = x*10+ch-'0';
    return x*op;
}
inline void write(ll a) {
    if(a < 0) putchar('-'), a = -a;
    if(a >= 10) write(a/10); putchar('0'+a%10);
}

const int N = 5005, M = 10005;
const int inf = 1e9;
int n, m, now;
int a[N], sum[N], f[M], g[M], b[N], pre[N][M];

int main() {
    n = read(); m = read();
    for(int i = 1; i <= n; i ++) sum[i] = sum[i-1]+(a[i] = read());
    //f[i][j]表示前i天得到了j元的代金券所用的最少錢數,加滾動數組
    memset(f, 0x3f, sizeof f);
    f[0] = 0;
    for(int i = 1; i <= n; i ++) {
        now = min(now+a[i]/10, M);
        for(int j = 0; j <= now; j ++) { g[j] = f[j]; f[j] = inf; }//滾動 
        for(int j = 0; j <= now; j ++) if(g[j] <= sum[i-1]) {//枚舉1~i-1天得到了多少代金券 
            int t = m-(sum[i-1]-g[j])+j;//sum[i-1]-g[j]就是1~i-1天用的代金券錢數 
            //t就是目前剩下的代金券錢數 
            for(int k = 0; k <= a[i]/2 && k <= t; k ++) {//枚舉第i天用多少代金券 
                int r = (a[i]-k)/10;//能獲得這麼多新的代金券
                if(g[j]+a[i]-k < f[j+r]) {
                    f[j+r] = g[j]+a[i]-k;
                    pre[i][j+r] = k;//記錄最優方案
                }
            }
        }
    }
    int ans = 0;
    for(int i = 1; i <= now; i ++) if(f[i] < f[ans]) ans = i;
    write(f[ans]); puts("");
    for(int i = n; i >= 1; i --) {
        b[i] = pre[i][ans];
        ans -= (a[i]-pre[i][ans])/10;
    }
    for(int i = 1; i <= n; i ++) write(b[i]), putchar(' ');
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章