题意:
k次操作 每次选择一行或一列 得到所选数字的和 并将所选数字同一时候减去p 问最多得到多少
思路:
重点在消除行列间的相互影响
因为每选一行全部列所相应的和都会-p 那么假设选了i次行 则列会-i*p 同理选列
那么影响就能够这样表示 -p*i*(k-i) 把影响提出来 这样行列就不影响了
对于行或列 单独处理时相当于一维的东西 贪心就可以
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define N 1010
#define M 1000010
typedef __int64 ll; ll sum[2][N];
ll res[2][M];
ll ans,p;
int n,m,k;
struct node
{
ll val;
int x;
bool operator<(const node fa) const
{
return val<fa.val;
}
}u;
priority_queue<node> q; int main()
{
int i,j;
ll w;
scanf("%d%d%d%I64d",&n,&m,&k,&p);
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%I64d",&w);
sum[0][i]+=w;
sum[1][j]+=w;
}
}
while(!q.empty()) q.pop();
for(i=1;i<=n;i++)
{
u.x=i;
u.val=sum[0][i];
q.push(u);
}
for(i=1;i<=k;i++)
{
u=q.top();
q.pop();
res[0][i]=res[0][i-1]+u.val;
u.val-=p*m;
q.push(u);
}
while(!q.empty()) q.pop();
for(i=1;i<=m;i++)
{
u.x=i;
u.val=sum[1][i];
q.push(u);
}
for(i=1;i<=k;i++)
{
u=q.top();
q.pop();
res[1][i]=res[1][i-1]+u.val;
u.val-=p*n;
q.push(u);
}
ans=max(res[0][0]+res[1][k],res[0][k]+res[1][0]); // hang or lie
for(i=1;i<k;i++) ans=max(ans,res[0][i]+res[1][k-i]-p*i*(k-i));
printf("%I64d\n",ans);
return 0;
}