【思维】Codeforces893D Credit Card

过了大概一个礼拜,不甘心地打了一场(首场RATED的ERs),C题再次暴露了我压力下思考不够深入的问题,最坏N方的算法显然超时了,不该偷这个懒,还好评测测了出来,虽然说那天晚上机器特别慢延误了15分钟。

题意: 这个题意就看了好久。一共N天,账户内存入最多D元,每天晚上余额会变动,避免某天账户持平而钱数小于0,或者晚上余额变动后余额大于D。每天早上都可以存任意多的钱直到D。

题解: 因为每天早上都能存钱而且能存到D因此不用担心a[I] = 0的日子钱数不够,要担心的是 钱太多超过D。于是乎,先计算前缀和算出不加钱的话每天账户里会有多少钱,用一个变量tmp记录已经加了多少钱。做一个o(n)的循环,先判断当前tmp加上之后最小的前缀和会不会超过D,如果是a[I]=0的点,判断下能不能过,不能的话加上能加的最大的数。

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const LL INF = (LL)1 << 62;

LL n, d;
LL a[100010];
LL s[100010];
LL top[100010];
LL mtop[100010];
LL ck[100010];

int main(){
    cin >> n >> d;
    for (int i = 1; i <= n; i++){
        scanf("%I64d", &a[i]);
        if (a[i] == 0) ck[i] = 1;
        s[i] = s[i - 1] + a[i];
        top[i] = d - s[i];
    }
    mtop[n + 1] = top[n];
    for (int i = n; i >= 1; i--){
        mtop[i] = min(mtop[i + 1], top[i]);
    }
    LL ans = 0; LL tmp = 0;
    for (int i = 1; i <= n; i++){
        if (s[i] + tmp > d){
            printf("-1\n");
            return 0;
        }
        if (ck[i]){
            if (s[i] + tmp >= 0) continue;
            else{
                if (mtop[i] + s[i]>= 0){
                    tmp = max(tmp, mtop[i]);
                    ans++;
                }
                else{
                    puts("-1");
                    //system("pause");
                    return 0;
                }
            }
        }
    }
    printf("%d\n", ans);
    //system("pause");
    return 0;
}

你可能感兴趣的:(【思维】Codeforces893D Credit Card)