持续创作,加速成长!这是我参与「掘金日新计划 · 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);
}