• 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
    ", u, ans);
        }
        return 0;
    }
    
  • 相关阅读:
    【小模块】公告滚动并暂停
    w3school的PHP教程提炼(一)PHP基础
    Nicholas C. Zakas:介紹CSS Lint(检测工具)
    【小模块】回到顶部的页面跟随按钮(仿淘宝)
    【小模块】内容循环滚动(仿新浪微博未登录首页滚动微博显示)
    前端管窥:图片Sprite管理
    《锋利的jQuery》要点归纳(六)插件的使用和写法
    CSS reset 一份很全的样式表
    《锋利的jQuery》要点归纳(五)jQuery与ajax的应用(上)
    《锋利的jQuery》要点归纳(五)jQuery与ajax的应用(下)
  • 原文地址:https://www.cnblogs.com/whisperlzw/p/11298214.html
Copyright © 2020-2023  润新知