牛客多校第九场 The Escape Plan of Groundhog(压缩行)

牛客多校第九场 The Escape Plan of Groundhog(压缩行)_第1张图片
题意:
要求存在寻找多少子矩阵,使得子矩阵边界都为1,且内部的0和1的数目相差不超过1。

思路:
直接枚举是 n 4 n^4 n4的,要优化到 n 3 n^3 n3则需要重复利用一些行的信息,比如可以用前缀和维护连续行连续列的信息(或者二维前缀和维护一个子矩阵)。

本题就是先确定上下界,再枚举其中的列,维护前面i列中0的数目和1的数目,并记录下前缀中每个值的出现次数。

则当连续几行的上界和下界都为1,且当前列都为1,则可以记录下这个前缀,在之前寻找同样的合法前缀,作差后就是一个合法子矩阵了。

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
typedef unsigned int uint;

const int maxn = 1e6 + 7;
const int det = 5e5 + 7;
int a[505][505],sum0[505],sum1[505];
int cnt0[505][505],cnt1[505][505];
int num[maxn];
vector<int>vis;

void init() {
    for(int i = 0;i < vis.size();i++) {
        num[vis[i]] = 0;
    }
    vis.clear();
}

int main() {
    int n,m;scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++) {
        for(int j = 1;j <= m;j++) {
            scanf("%d",&a[i][j]);
        }
    }
    
    int ans = 0;
    for(int i = 1;i <= n;i++) { //上界
        for(int j = 1;j <= m;j++) {
            cnt0[i][j] = (a[i][j] == 0);
            cnt1[i][j] = (a[i][j] == 1);
        }
        for(int j = i + 1;j <= n;j++) { //下界
            sum0[0] = sum1[0] = 0;
            for(int k = 1;k <= m;k++) {
                cnt0[j][k] = cnt0[j - 1][k] + (a[j][k] == 0);
                cnt1[j][k] = cnt1[j - 1][k] + (a[j][k] == 1);
                sum0[k] = sum0[k - 1] + cnt0[j][k];
                sum1[k] = sum1[k - 1] + cnt1[j][k];
                if(a[j][k] != 1 || a[i][k] != 1) {
                    init();continue;
                }
                
                if(cnt1[j][k] == j - i + 1) {
                    int vinsert = sum1[k] - sum0[k] - k * 2 + det;
                    int vquery = sum1[k - 1] - sum0[k - 1] - (k - 1) * 2 + det;
                    ans += num[vquery] + num[vquery - 1] + num[vquery + 1];
                    num[vinsert]++;
                    vis.push_back(vinsert);
                }
            }
            init();
        }
    }
    
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(#,其他比赛题目)