[NOIP 2023 模拟7]矩阵游戏
[NOIP 2023 模拟7]矩阵游戏
=> 题意:
这是一个n行m列的矩阵,将进行k次操作,每次操作将矩阵的某一行或某一列的所有元素的值减p,得分为修改前这一行或这一列的元素和。
求出k次操作能获得的分数的最大值。
=> 思路:
考虑贪心:我们每次选择 max(行max, 列max),并计入答案、减去相应的值
如果最优选择一直位于 行上 或 列上,则上述做法是正确的
但如果数据不保证上述条件......
举出反例:
2 5 5 5
5 5 5 5 5
1 1 1 1 1
所以换思路:
注意到:列上的操作对行上的操作是没有影响的,同样的,行上操作对列上操作没有影响
于是行和列分开贪心:前i次都用行删除的答案为f_i,前i次都用列删除的答案为g_i,则答案为 max(f_i+g_(k-i)−1LL*i∗(k−i)∗p)
=> 代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N=1e6+10;
LL n,m,k,p;
LL mapp[1001][1001];
LL hang[N],lie[N];
priority_queue<LL> q;
int main() {
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n>>m>>k>>p;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
cin>>mapp[i][j];
}
}
for(int i=1;i<=n;i++) {
LL sum=0;
for(int j=1;j<=m;j++) {
sum+=mapp[i][j];
}
q.push(sum);
}
for(int i=1;i<=k;i++) {
LL tmp=q.top();
q.pop();
hang[i]=hang[i-1]+tmp;
q.push(tmp-m*p);
}
while(!q.empty()) q.pop();
for(int i=1;i<=m;i++) {
LL sum=0;
for(int j=1;j<=n;j++) {
sum+=mapp[j][i];
}
q.push(sum);
}
for(int i=1;i<=k;i++) {
LL tmp=q.top();
q.pop();
lie[i]=lie[i-1]+tmp;
q.push(tmp-n*p);
}
LL ans=-LLONG_MAX;
for(int i=0;i<=k;i++) {
ans=max(ans,hang[i]+lie[k-i]-1LL*i*(k-i)*p);
}
cout<<ans;
return 0;
}