给定一个n * mn∗m的矩阵,将对矩阵进行k次操作。每次可以进行如下某一种操作:
1.将某行的元素相加作为快乐值,然后将该行元素都减去p。
2.将某列的元素相加作为快乐值,然后将该列元素都减去p。
问k次之后快乐值总和的最大值是多少?
输入
第一行输入四个整数n, m, k, p (1 \le n, m \le 10^3, 1 \le k \le 10^6, 1 \le p \le 10^2)n,m,k,p(1≤n,m≤103,1≤k≤106,1≤p≤102)。
接下来n行,每行m个整数表示矩阵。
矩阵中的元素属于区间[1, 10^3][1,103]。
输出
输出最大快乐值总和。
样例
输入
复制
2 2 2 2 1 3 2 4
输出
复制
11
提示
先对第二列操作,然后对第二行操作
最后矩阵变成
1 1
0 0
子任务1,20分,2 \le n + m \le 10, 1 \le k \le 32≤n+m≤10,1≤k≤3。
子任务2, 80分,1 \le n, m \le 10^3, 1 \le k \le 10^61≤n,m≤103,1≤k≤106。
先找行还是先找列都是一样的,因为对行操作后,对列的和产生的影响是一样,反之也是如此,枚举所有的可能,找所有和的和最大的。
#include <iostream> #include <cstdio> #include <queue> #include <cstring> #include <vector> #include <algorithm> #include <functional> #define inf 0x3f3f3f3f int main() { int n, m, d, k, p; scanf("%d %d %d %d", &n, &m, &k, &p); std::vector<int> rsum(n, 0); std::vector<int> csum(m, 0); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { scanf("%d", &d); rsum[i] += d; csum[j] += d; } } std::vector<long long> sum(k + 1, 0); std::priority_queue<long long, std::vector<long long>, std::less<long long>> qr, qc; for (int i = 0; i < n; i++) { qr.push(rsum[i]); } for (int i = 0; i < m; i++) { qc.push(csum[i]); } long long ssumr = 0, ssumc = 0, temp; for (int i = 1; i <= k; i++) { temp = qr.top(); qr.pop(); qr.push(temp - m * p); ssumr += temp; sum[i] += ssumr; temp = qc.top(); qc.pop(); qc.push(temp - n * p); ssumc += temp; sum[k - i] += ssumc; if (i * 2 <= k) { temp = (long long)i * (k - i) * p; sum[i] -= temp; if (i != k - i) sum[k - i] -= temp; } } long long ans = sum[0]; for (int i = 1; i <= k; i++) { if (sum[i] > ans) { ans = sum[i]; } } printf("%lld", ans); return 0; }
如果觉得有帮助,点个推荐啦~