zoukankan      html  css  js  c++  java
  • GMOJ 6860. 【2020.11.14提高组模拟】鬼渊传说(village)

    题解

    这题考场打了60分,没想到80分。

    这题我从听完题思考了一下细节就开始打,除掉5:00到7:00的洗澡+吃饭+腐败,一直打到晚上9:00才切。

    感谢出题人,对我的心态锻炼起到了很大的作用。

    不过yysy,这题打完的收获还是挺大的。

    60分悬线法,很裸。

    80分的做法要判断联通性,可以考虑用欧拉公式:

    以下内容摘自OI wiki

    对于任意的连通的平面图 (G),有:

    [n+r-m=2 ]

    其中,(n,m,r)分别为(G)的阶数(顶点数),边数,面数。

    而对于这道题而言,面数(r)显然就是四点环的个数+1,如果一个子矩阵有且仅有一个连通块,显然当且仅当他满足欧拉公式。

    证明很简单,在此省略。

    具体做法就是对于预处理出顶点数,边数,四点环数的前缀和,这个东西比较ex,反正我是处理了7个前缀和来维护。

    主要是这个东西不能像普通的前缀和一样直接做差,要判断相邻的点之间的影响。

    然后就可以枚举上,下,右边界,然后用一个桶来维护个数,在里面统计答案。

    然后对于满分算法,也就是处理空腔:

    • 考虑将所有空腔预处理出来,找到包含每个空腔的最小子矩阵。
    • 然后将这些空腔以子矩阵的下边界排序。
    • 每次枚举到上边界时,将这个边界下方的空腔统计出来。
    • 然后用一个指针,每次将当前枚举到的范围内的空腔找出来,以此来确定左边界的范围。
    • 再用一个指针维护桶就行了。

    思路不难,但是知识点不会,细节非常之多。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 500
    using namespace std;
    int n,m,i,j,k,ans,bkt[N*N*10],bz[N][N],map[N][N],num,x0,y0,x1,y1,fx[5][3],lim[N],p,data[N*N],tot,q;
    int sumh[N][N],suml[N][N],sumh1[N][N],suml1[N][N];
    char ch[N];
    struct empty{
    	int x0,y0,x1,y1;
    }fp[N*N];
    struct sumf{
    	int node,edge,mian;
    }sum[N][N];
    void dfs(int x,int y){
    	int i,xx,yy;
    	bz[x][y]=1;
    	x0=min(x,x0);y0=min(y,y0);
    	x1=max(x,x1);y1=max(y,y1);
    	for (i=1;i<=4;i++){
    		xx=x+fx[i][1];yy=y+fx[i][2];
    		if (bz[xx][yy]==0&&map[xx][yy]==0&&xx>0&&yy>0&&xx<=n&&yy<=m)
    			dfs(xx,yy);
    	}
    }
    int cmp(empty x,empty y){
    	return x.x1<y.x1;
    }
    int solve(int l,int r,int k){
    	int s1=sum[r][k].node-sum[l][k].node;
    	int s2=sum[r][k].edge-sum[l][k].edge-sumh[l+1][k];
    	int s3=sum[r][k].mian-sum[l][k].mian-sumh1[l+1][k];
    	return s1+s3-s2;
    }
    int main(){
    	freopen("village.in","r",stdin);
    	freopen("village.out","w",stdout);
    	fx[1][1]=1;fx[1][2]=0;
    	fx[2][1]=-1;fx[2][2]=0;
    	fx[3][1]=0;fx[3][2]=1;
    	fx[4][1]=0;fx[4][2]=-1;
    	scanf("%d%d
    ",&n,&m);
    	for (i=1;i<=n;i++){
    		scanf("%s
    ",ch+1);
    		for (j=1;j<=m;j++) map[i][j]=ch[j]-'0';
    	}
    	for (i=1;i<=n;i++)
    		for (j=1;j<=m;j++)
    			if (bz[i][j]==0&&map[i][j]==0){
    				x0=y0=1e9;x1=y1=0;
    				dfs(i,j);
    				if (x0>1&&y0>1&&x1<n&&y1<m)
    					fp[++num]=(empty){x0,y0,x1,y1};
    			}
    	for (i=1;i<=n;i++)
    		for (j=1;j<=m;j++){
    			sum[i][j].node=sum[i-1][j].node+sum[i][j-1].node-sum[i-1][j-1].node+(map[i][j]==1);
    			sum[i][j].edge=sum[i-1][j].edge+sum[i][j-1].edge-sum[i-1][j-1].edge+(map[i][j]==1&&map[i-1][j]==1)+(map[i][j]==1&&map[i][j-1]==1);
    			sum[i][j].mian=sum[i-1][j].mian+sum[i][j-1].mian-sum[i-1][j-1].mian+(map[i][j]==1&&map[i-1][j]==1&&map[i][j-1]==1&&map[i-1][j-1]==1);
    			sumh[i][j]=sumh[i][j-1]+(map[i][j]==1&&map[i-1][j]==1);
    			suml[i][j]=suml[i-1][j]+(map[i][j]==1&&map[i][j+1]==1);
    			sumh1[i][j]=sumh1[i][j-1]+(map[i][j]==1&&map[i-1][j]==1&&map[i][j-1]==1&&map[i-1][j-1]==1);
    			suml1[i][j]=suml1[i-1][j]+(map[i][j]==1&&map[i-1][j]==1&&map[i][j+1]==1&&map[i-1][j+1]==1);
    		}
    	sort(fp+1,fp+num+1,cmp);
    	for (i=1;i<=n;i++){
    		tot=0;
    		for (j=1;j<=num;j++)
    			if (i<fp[j].x0) data[++tot]=j;
    		for (j=1;j<=m;j++) lim[j]=0;
    		p=0;
    		for (j=i;j<=n;j++){
    			while (j>fp[data[p+1]].x1&&p+1<=tot) lim[fp[data[p+1]].y1+1]=max(lim[fp[data[p+1]].y1+1],fp[data[p+1]].y0-1),p++;
    			q=0;
    			if (i==1&&j==3){
    				int lsp=0;
    			}
    			for (k=1;k<=m;k++){
    				k--;
    				bkt[solve(i-1,j,k)-(suml[j][k]-suml[i-1][k])+(suml1[j][k]-suml1[i-1][k]-(map[i][k]==1&&map[i][k+1]==1&&map[i-1][k]==1&&map[i-1][k+1]==1))+1+n*n]++;
    				k++;
    				while (q+1<=lim[k]&&q<=m) bkt[solve(i-1,j,q)-(suml[j][q]-suml[i-1][q])+(suml1[j][q]-suml1[i-1][q]-(map[i][q]==1&&map[i][q+1]==1&&map[i-1][q]==1&&map[i-1][q+1]==1))+1+n*n]--,q++;
    				ans+=bkt[solve(i-1,j,k)+n*n];
    			}
    			q=0;
    			for (k=1;k<=m;k++){
    				k--;
    				bkt[solve(i-1,j,k)-(suml[j][k]-suml[i-1][k])+(suml1[j][k]-suml1[i-1][k]-(map[i][k]==1&&map[i][k+1]==1&&map[i-1][k]==1&&map[i-1][k+1]==1))+1+n*n]--;
    				k++;
    				while (q+1<=lim[k]&&q<=m) bkt[solve(i-1,j,q)-(suml[j][q]-suml[i-1][q])+(suml1[j][q]-suml1[i-1][q]-(map[i][q]==1&&map[i][q+1]==1&&map[i-1][q]==1&&map[i-1][q+1]==1))+1+n*n]++,q++;
    			}
    		}
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    repo
    manifest
    Gerrit使用简介
    id_rsa id_rsa.pub
    数字签名原理及其应用
    RSA DSA
    ssh(安全协议外壳)
    Numpy基本数据结构
    Numpy
    .bat 批处理
  • 原文地址:https://www.cnblogs.com/Mohogany/p/13974869.html
Copyright © 2011-2022 走看看