时间:1s 空间:32M
题目描述:
有一个 n×m的矩阵,现在准备对矩阵进行k次操作,每次操作可以二选一
1:
选择一行,给这一行的每一个数减去p,这种操作会得到的快乐值等于操作之前这一行的和
2:
选择一列,给这一列的每一个数减去p,这种操作会得到的快乐值等于操作之前这一列的和
那么问题来了,k次操作最大可能得到的和是多少。
输入格式:
第一行输入4个整数n,m,k,p
接下来n行,每行输入m个整数a[i][j]
输出格式:
输出最大可能的和
样例输入1:
2 2 2 2
1 3
2 4
样例输出1:
11
样例输入2:
5 5 20 100
464 757 53 708 262
753 769 189 38 796
394 60 381 384 935
882 877 501 615 464
433 798 504 301 301
样例输出2:
38013
样例输入3:
2 1 3 2
3
3
样例输出3:
8
约定:
1≤n,m≤1000,1≤k≤106,1≤p,a[i][j]≤1000
---------------------------------------------------------题解分割线--------------------------------------------------------------
看到是求最大和,不可避免的考虑到贪心
那么来考虑一下贪心的正确性
首先考虑取行列的相互影响关系:可以发现当取x次行时,取了(k-x)次列
每取1次行,这一行的和会减少m*p,每一列的和会减少p
同样的每取1次列,这一列的和会减少n*p,每一行的和会减少p
然后考虑取行列的顺序关系:可以发现先取行和先取列对于答案的贡献是一样的
所以在取行列数量确定的情况下,取行列的顺序是没有影响的,所以考虑每次取大值得做法是正确的
那么只需要枚举取0到k次行,同时可以枚举出(k-0)次列的答案情况,然后ans取最大值即可
既然贪心是可行的,那么再考虑一下复杂度的问题,
如果每取一次就模拟的把每个数减去p的话,时间复杂度是O(n^2*m^2*k*log(n)*log(m)),肯定会T
所以我们考虑先把每行每列的和预处理出来一起处理,这样时间复杂度就是O(k*log(n)*log(m)),完全OK
(重要重要重要)PS. 数据十分毒瘤,inf一定要开的够大
-------------------------------------------------------代码分割线----------------------------------------------------------------
以下是AC代码:
#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
typedef long long LL;
static const int N = 1010;
static const int M = 1e6 + 10;
static const LL inf = 99999999999999999;
LL n, m, p, k, ans = -inf;
LL mp, h[N], l[N], ansh[M], ansl[M];
priority_queue <LL> qh;
priority_queue <LL> ql;
int main ()
{
scanf ("%lld%lld%lld%lld", &n, &m, &k, &p);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
{
scanf ("%lld", &mp);
h[i] += mp;
l[j] += mp;
}
for (int i = 1; i <= n; ++i)
qh.push(h[i]);
for (int i = 1; i <= m; ++i)
ql.push(l[i]);
ansh[0] = ansl[0] = 0;
for (int i = 1; i <= k; ++i)
{
LL x = qh.top();
LL y = ql.top();
qh.pop();
ql.pop();
ansh[i] = ansh[i-1] + x;
ansl[i] = ansl[i-1] + y;
qh.push(x-p*m);
ql.push(y-p*n);
}
for (int i = 0; i <= k; ++i)
{
ans = max (ansh[i] + ansl[k-i] - (k-i) * i * p, ans);
}
printf ("%lld", ans);
}