zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    boost 1.49在vs 2005下编译的方法
    Mathematics for Computer Graphics
    字符串和字符数组长度
    四个月的学习心得
    话说stm32f10x-FSMC的配置与频率
    一些笔试题,大家都来围观呀~
    简单的生产者消费者-(windows下)
    STM32f10x下软件模拟IIc读写si5326问题
    usb枚举阶段(转载)
    STM32 GPIOB_PIN3复用功能小分析
  • 原文地址:https://www.cnblogs.com/whisperlzw/p/11298214.html
Copyright © 2011-2022 走看看