P7741 [AHOI2007] 石块地板

FBI Warning

此题是一道思维题,请不要"对着题解调试程序"(大雾

前置芝士

一维前缀和(就够了)

最大子段和(P1115

二维数组(能做到蓝题的应该都会吧

思路

注意,这题的 nm 是和其他题反过来的!

这题明显是一个卡了我两天的最大子矩阵和板子题。

有同学就要问了:那为什么是“和”呢?问的是“差最大”啊?

但是这个“差最大”问题也可以转换成“和最大”问题。

黑(的数目) - 白(的数目)最大,即要求黑尽可能多,白尽可能少。

令黑色表示 1,白色表示 1,即“1 尽可能多,1 尽可能少”。

1 尽可能多,所有 11 的和就尽可能大。

1 尽可能少,所有 11 的和也尽可能大。

反过来,只要所有 11 的和尽可能大,1 就多,1 就少,(数目的)差也就大。

所以保证矩阵内的 11 的和尽可能大即可,差即为 11 的和。

是不是恍然大明白?(我猜你没有

那么怎么找出这个“和最大”的子矩阵呢?枚举,但不是直接暴力。

首先,在矩阵上划定一个范围:

枚举这个范围需要 n2 的复杂度,子矩阵将在这个范围中确定。

将这个范围中每行的和算出来:

si 表示第 i 行每个数的和,灰框是一个临时的数组。

每行的和需要 nm 的复杂度,但可以用前缀和优化成 O(m)

那么,这个范围就被抽象成了灰框内的数组。

算这个数组的最大子段和,最大的子段就对应着最大的矩阵。

这样,最大矩阵就找到了,复杂度 O(n2m)

代码

#include <iostream>
#define qjh(r, x, y) s[r][y] - s[r][x - 1]
using namespace std;
int s[401][401], t[401], m, n, ans;char c;
void get()
{
    for(int i = 1;i <= m;++i)
    {
        t[i] = max(t[i], t[i] + t[i - 1]);
        ans = max(ans, t[i]);
    }
}
int main()
{
    cin >> m >> n;
    for(int i = 1;i <= m;++i)
        for(int j = 1;j <= n;++j)
        {
            cin >> c;
            if(c == '1') s[i][j] = s[i][j - 1] + 1;
            if(c == '0') s[i][j] = s[i][j - 1] - 1;
        }
    for(int i = 1;i <= n;++i)
        for(int j = i;j <= n;++j)
        {
            for(int k = 1;k <= m;++k)
                t[k] = qjh(k, i, j);
            get();
        }
    cout << ans;
    return 0;
}
posted @   Jijidawang  阅读(2)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示