题目链接:点击打开链接
题意:
给定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
*/