P7741 [AHOI2007] 石块地板 题解
Micnation_AFO · · 题解
- 原题面
- 更好的阅读体验
题目大意 :给出一个
具体思路 :
-
求出每一行前
j 个数的前缀和。即:sum_{i,j} = sum_{i,j-1} + a_{i,j} 其中,
sum_{i,j} 表示第i 行前j 个数的前缀和。 -
进行枚举起始列
i 与目标列j ,再把每一行中从i 到j 的和算出来(利用之前的前缀和),我们可以建立一个 临时 数组f1,则:f_k = sum_{k,j} - sum_{k,i-1} 其中,
f_k 表示第k 行中从i 到j 的和。 -
这时,我们已经把每一行(从
i 到j )的和存到了数组f 中,那么我们就可以把问题转化为 最大子段和 问题了。最大子段和的公式:f_k = \max(f_k, f_k + f_{k - 1}) 再用变量
ans 打擂台求出f_k 的最大值即可。
AC Code :
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 405
int m, n, ans;
int sum[maxn][maxn], f[maxn];
char c;
signed main() {
cin >> m >> n;
//注意不是 n 行 m 列
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++) {
cin >> c;
if (c == '1') sum[i][j] = sum[i][j - 1] + 1;
else if (c == '0') sum[i][j] = sum[i][j - 1] - 1;
}
//求出每一行的前 j 个数的前缀和
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++) {//枚举第 i 列到第 j 列
for (int k = 1; k <= m; k++)
f[k] = sum[k][j] - sum[k][i - 1];//把每一行的和算出来
for (int k = 1; k <= m; k++) {
f[k] = max(f[k], f[k] + f[k - 1]);
ans = max(ans, f[k]);
}//最大子段和问题
}
cout << ans << endl;
return 0;
}