2019頭の牛のオフより学校第六J-アップグレードテクノロジー(+単調列挙キュー)

アップグレードテクノロジ

トピックポータル

問題解決のためのアイデア

この問題のために、私たちは現在の最小レベルをk、kは上昇し、少なくとも1つのレベルがある表し、すべてのスキルを入れて、0〜Mからk個を列挙することができます。

この時点で、私たちは最初のk dを[]の利益を獲得し、そしてそれはレベルkに上昇するのにかかるすべてのスキルを過ごしました。今、我々は(現在の状況下で最大の利益を得るために、我々は、このスキルを通じて最大の利益を得ることができるように、一定のレベルにそれぞれのスキルをアップグレードし続ける必要があり、kに上昇する、すなわち最小コストを、すべてのスキルを持っているので、 )、即ち、S [K〜M]最小 - S [k]は(S [])このスキルおよび費用の接頭辞です。私たちは、この最小値を維持するために、単調なキューを使用することができます。しかし、我々は、我々は所得の列挙を満たしていない現時点では、すべてのスキルが最大と利益を上げることができ、すべてのスキルレベルがk個以上のものになります問題は、ただ最初のk dを[]のを取得しています「条件が、私たちは最大のコストの1を追加する必要があり、少なくとも一つのスキルレベルは正確に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