首页 > 代码库 > Codeforces 446B DZY Loves Modification 矩阵行列分开考虑 优先队列+构造

Codeforces 446B DZY Loves Modification 矩阵行列分开考虑 优先队列+构造

 题目链接:点击打开链接

题意:

给定n行m列的矩阵 k次操作,一个常数p

ans = 0;

对于每次操作

可以任选一行或一列, 则ans += 这行(列)的数字和

然后这行(列)上的每个数字都-=p


问最大的ans


思路:

首先我们设最终选了 行 i 次,则列选了 k-i 次

那么假设我们先全部选行,然后选列,则每次选列时,要-= i*p

这样最后是 -= i*(k-i)*p

也就是所有行对列的影响

那我们先把这个 i*(k-i)*p 提出来,那么选行和选列就互不影响

就可以分别考虑行和列

对于只取行的情况:

预处理出选0次 1次······k次行的最大值 H[i]

即优先队列跑一次即可

同理对列处理, 得到 L[i] 表示取i次列, 0次行的最大值

然后 ans = max( H[i]+L[k-i] - i*(k-i)*p )

注意结果可能是很小的负数,ans = -inf ,inf要足够大

#include <cstdio>
#include <algorithm>
#include<iostream>
#include<string.h>
#include <math.h>
#include<queue>
using namespace std;
#define ll long long
#define N 1005
#define M 1000005
ll a[N][N];
ll retc[M], retr[M];
priority_queue<pair<ll, ll> > sc, sr;
int main() {
	ll n, m, k, p;
	while(cin>>n>>m>>k>>p){
            while(!sc.empty())sc.pop();
    while(!sr.empty())sr.pop();
        for(ll i = 1; i <= n; i ++) {
            for(ll j = 1; j <= m; j ++) {
                scanf("%I64d", &a[i][j]);
            }
        }
        for(ll i = 1; i <= n; i ++) {
            ll s = 0;
            for(ll j = 1; j <= m; j ++) {
                s += a[i][j];
            }
            sr.push(make_pair(s, i));
        }
        for(ll j = 1; j <= m; j ++) {
            ll s = 0;
            for(ll i = 1; i <= n; i ++) {
                s += a[i][j];
            }
            sc.push(make_pair(s, j));
        }
        for(ll i = 1; i <= k; i ++) {
            ll s = sr.top().first;
            ll id = sr.top().second;
            retr[i] = retr[i-1] + s;
            s -= p*m;
            sr.pop();
            sr.push(make_pair(s, id));
        }
        for(ll i = 1; i <= k; i ++) {
            ll s = sc.top().first;
            ll id = sc.top().second;
            retc[i] = retc[i-1] + s;
            s -= p*n;
            sc.pop();
            sc.push(make_pair(s, id));
        }
        ll ans = -(ll)(1e18);
        for(ll i = 0; i <= k; i ++) {
            ans = max(ans, retr[i] + retc[k-i] - (ll)i * (k-i) * p);
        }
        cout<<ans<<endl;
    }
	return 0;
}


/*
2 2 2 2
1 3
2 4

2 2 5 2
1 3
2 4

3 1 3 1
3
2
1

3 2 4 1
1 1
1 1
1 1

3 1 3 1
0
0
0

2 3 3 2
1 1 -1
-1 1 1

1 5 21 1
1 2 3 4 5 6


*/