2022hecpc7-13 裁纸游戏

133 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情

你有一张 n 行 m 列的网格纸,每个格子上有一个整数。对于一张网格纸 X,定义 w(X) 为 X 所有格子上的整数之和。

在裁纸游戏中,你可以通过如下规则得分(初始分数为 0):

选择一张网格纸 Y,将 Y 沿着非边界的网格线(相邻的两行或两列之间的线,而不是边界)剪开,得到两张新的网格纸 Y1​,Y2​。通过这次裁剪,你可以获得 w(Y1​)×w(Y2​) 的分数。

你可以进行任意次(包括零次)的裁剪操作,试最大化你的得分,并输出这个分数。

Input

第一行包含两个正整数 n,m(1≤n×m≤106).

接下来 n 行,每行 m 个整数 ai,1​,ai,2​,⋯,ai,m​. 保证 0≤ai,j​≤103.

Output

一行一个整数,表示可能的最大得分。

Sample Input 1

1 2
3 3

Sample Output 1

9

Sample Input 2

2 2
0 0
0 1000

Sample Output 2

0

思路:公式加前缀和

首先题意是把纸分成几块,但是每次只对分的计算

例如:1 2 3 4

把它先分成两张假设是{1},{2,3,4},此时是1*(2+3+4),再对{2,3,4}分开,假设是{2},{3,4}那么就是2*(3+4)再加上之前的1*(2+3+4),要最大就是分成单元格,同时根据这个规律你就可以得到答案是

a1(a2+a3....+a(ij))+a2(a3+a4+.....+a(ij))+.....+a(ij-1)a(ij);

但是这是1e6,如果遍历的话会超时,那么我们可以借助前缀和的思想,把所有的和求出来sum那么

a1(a2+a3....+a(i*j)) == a1(sum-a1)

以此类推就可以O(n)的复杂度跑完

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    vector<ll>ans;
    ll num = 0;
    for(int i = 1;i <= n;i ++)
    {
        for(int j = 1;j <= m;j ++)
        {
            int x;
            cin >> x;
            ans.push_back(x);
            num += x;
        }
    }
    ll sum = 0;
    for(int i = 0;i < ans.size();i ++)
    {
        num -= ans[i];
        sum += num * ans[i];
    }
    printf("%lld\n",sum);
}