2019牛客多校第六场J-Upgrading Technology(枚举+单调队列)

Upgrading Technology

题目传送门

解题思路

对于这题,我们可以枚举一个k从0~m,表示当前我们把所有技能最少升到了k级,且至少有一个为k级。

此时我们刚好获得了前k个d[]的收益,并花费了所有技能升到k级的花费。因为现在我们已经把所有技能都升到k了,为了获得当前情况下的最大收益,我们要把每一个技能继续升级到一定的等级,使我们能够通过这一技能获得最大的收益(即最小花费),即s[k~m]的最小值 - s[k] (s[]为这一技能花费的前缀和)。我们可以用单调队列来维护这个最小值。但是还有一个问题,就是可能我们让所有技能的获利都最大时,会使所有技能的等级都超过了k,此时就不满足我们枚举时‘刚好获得前k个d[]的收益’的条件了,所以我们要加上其中的最大花费,使至少一个技能等级刚好等于k,并且损失最小。

最后的答案就是枚举的情况中的最大值。

代码如下

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;

inline int read(){
    int res = 0, w = 0; char ch = 0;
    while(!isdigit(ch)){
        w |= ch == '-', ch = getchar();
    }
    while(isdigit(ch)){
        res = (res << 3) + (res << 1) + (ch ^ 48);
        ch = getchar();
    }
    return w ? -res : res;
}

const int N = 1005;

ll c[N][N], s[N][N];
ll d[N];

int main()
{
    int _ = read();
    for(int u = 1; u <= _; u ++){
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i ++){
            for(int j = 1; j <= m; j ++)
                scanf("%lld", &c[i][j]);
        }
        for(int j = 1; j <= m; j ++)
            scanf("%lld", &d[j]);
        ll t[N];
        t[0] = 0;
        for(int j = 1; j <= m; j ++){
            ll w = 0;
            for(int i = 1; i <= n; i ++)
                w += c[i][j];
            t[j] = d[j] - w + t[j - 1];
        }
        deque<int> dq[N];
        for(int i = 1; i <= n; i ++){
            for(int j = 0; j <= m; j ++){
                s[i][j] = s[i][j - 1] + c[i][j];
                while(!dq[i].empty() && s[i][dq[i].back()] >= s[i][j])
                    dq[i].pop_back();
                dq[i].push_back(j);
            }
        }
        ll ans = 0;
        for(int j = 0; j <= m; j ++){
            ll temp = t[j];
            ll mx = -2223372036854775808LL;
            for(int i = 1; i <= n; i ++){
                while(!dq[i].empty() && dq[i].front() < j)
                    dq[i].pop_front();
                int top = dq[i].front();
                ll r = s[i][top] - s[i][j];
                mx = max(mx, r);
                temp -= r;
            }
            temp += mx;
            ans = max(ans, temp);
        }
        printf("Case #%d: %lld\n", u, ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/whisperlzw/p/11298214.html