Codeforces Round #FF (Div. 2) D. DZY Loves Modification

題目鏈接

http://codeforces.com/contest/447/problem/D

題目大意

給你一個矩陣, 設答案爲ans = 0, 讓你進行k次操作, 每次操作爲選取一行或一列, ans+=該行或列所有元素之和, 加完後再把該行或列所有元素減去p
問你ans最大爲多少

思路

首先這題的難點就是取行的時候會影響列, 取列的時候會影響行
那我們乾脆先別考慮這些, 用r[i] 表示取i次行能得到的最大值
c[i]表示取i次列能得到的最大值
那麼ans = max(ans, c[i] + r[k - i] - i * (k - i) * p)
我們來理解一下爲什麼要減去i * (k - i) * p
取一次行的話, 每取一次列都多加了一個p
以此類推

實現

我們可以先記錄每一行的值的和cr[i], 以及每一列值的和cc[i], 再計算c[i], 以及r[i]的時候用兩個優先隊列來保證每次拿出的都是最大值

代碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll r[1000005], c[1000005], cr[1005], cc[1005];
priority_queue<ll>qc, qr;
int main()
{
    ll n, m, k, p;
    scanf("%I64d%I64d%I64d%I64d", &n, &m, &k, &p);
    for(int i=0; i<n; ++i)
    {
        ll tmp = 0, sr = 0, sc = 0;
        for(int j=0; j<m; ++j)
        {
            scanf("%I64d", &tmp);
            cc[j] += tmp;
            cr[i] += tmp;
        }
    }
    for(int i=0; i<m; ++i)
        qc.push(cc[i]);
    for(int i=0; i<n; ++i)
        qr.push(cr[i]);
    c[0] = 0, r[0] = 0;
    for(int i=1; i<=k; ++i)
    {
        int tmp = qc.top();
        qc.pop();
        c[i] = c[i-1] + tmp;
        qc.push(tmp - n*p);
    }
    for(int i=1; i<=k; ++i)
    {
        int tmp = qr.top();
        qr.pop();
        r[i] = r[i-1] + tmp;
        qr.push(tmp - m*p);
    }
    ll ans = -INF;
    for(ll i=0; i<=k; ++i)
        ans = max(ans, r[i] + c[k-i] - (k-i)*i*p);
    printf("%I64d\n", ans);
    return 0;
}

反思

  • 半個多月前這題毫無思路, 現在完全能獨立思考出思路並且實現了, 果然還是變強了哇哈哈
  • 在思考如何保證每次選擇都是最大值的時候卡了一下, 一下子沒想到有優先隊列這個東西, 一直在想別的辦法更新,實在是太蠢了
  • 這題出現了兩個bug, 一個是好像爆了int, 第二個把ans初始值賦爲0去更新, 答案可能會小於0沒考慮到
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章