给定一个n * mnm的矩阵,将对矩阵进行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(1n,m103,1k106,1p102)。

接下来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 32n+m10,1k3。

子任务2, 80分,1 \le n, m \le 10^3, 1 \le k \le 10^61n,m103,1k106。

 

先找行还是先找列都是一样的,因为对行操作后,对列的和产生的影响是一样,反之也是如此,枚举所有的可能,找所有和的和最大的。

#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;
}

 

分类:

技术点:

相关文章: