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没考虑到
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章