zoukankan      html  css  js  c++  java
  • P3631 [APIO2011]方格染色 带权并查集

    题意:

    给定大小为\(n*m\)的矩阵,对矩阵进行染色,颜色只有两种,要求矩阵内任意大小为\(2*2\)的子矩阵颜色只能为1种颜色3个,另1种颜色1个,现在固定k个格子的颜色,求有多少种染色方案

    范围&性质:\(1\le n,m,k\le 10^5\)

    分析:

    不看题解,我可能都想不出来,这是一道并查集

    我们可以利用位运算对题目进行简化,对于每一个2*2的矩阵,按题目要求异或得到的值为1,即存在$ a(i,j); xor ;a(i+1,j); xor ; a(i,j+1); xor ;a(i+1,j+1)=1\(,递推可以得到,第一行和第一列确定后,整张图的颜色也随之确定。反之,如果\)(x,y)\(的值确定,对\)(1,1)$也会有所限制

    分情况讨论:

    1. \((x,y)\)都为偶数时,以\((1,1),(x,y)\)为顶点的四边形内共有奇数个格子,异或和为1,且除了\((1,1),(x,1),(1,y),(x,y)\)以外的格子都异或了偶数次,可以得到

      \[a(1,1)\; xor \;a(x,1)\; xor \; a(1,y)\; xor \;a(x,y)=1 \]

      \[a(1,1)\; xor \;a(x,1)\; xor \; a(1,y) =1\;xor \;a(x,y) \]

    2. \((x,y)\)至少一个为奇数时,情况刚好相反,留给读者思考

    所以\(a(x,y)\)\(a(1,1)\)有三种关系,相同,相反,无关,前两种关系都可以看做联通,最后只需要统计\(a(1,1)=0 \ | \ 1\)时,全图有多少个连通块,答案即为\(2^{连通块个数-1}\),因为\(a(1,1)\)固定

    tips:

    1. 对于\(a(1,1)=1\)的情况只需要将所有固定的块颜色翻转,然后当做\(a(1,1)=0\)处理就好了

    2. 对于\(a(x,y)\)坐标均为偶数的情况将颜色翻转后当做第二种情况(至少一个为奇数)处理就好

      代码:

      #include<bits/stdc++.h>
      
      using namespace std;
      
      namespace zzc
      {
      	const int mod =1e9;
          const int maxn = 2e5+5;
          int n,m,k;
          int x[maxn],y[maxn],w[maxn],fa[maxn],g[maxn];
          
          int qpow(int x,int y)
          {
          	int res=1;
          	while(y)
          	{
          		if(y&1) res=(long long)res*x%mod;
          		x=(long long)x*x%mod;
          		y>>=1;
      		}
      		return res;
      	}
          
          int find(int x)
          {
          	if(x==fa[x]) return x;
          	int fx=find(fa[x]);
          	g[x]^=g[fa[x]];
          	return fa[x]=fx;
      	}
          
          int work(int opt)
          {
          	for(int i=1;i<=n+m;i++)
          	{
          		fa[i]=i;
          		g[i]=0;
      		}
      		fa[n+1]=1;
          	if(opt==1)
          	{
          		for(int i=1;i<=k;i++)
          		{
          			if(x[i]>1&&y[i]>1)
          			{
          				w[i]^=1;
      				}
      			}
      		}
      		for (int i=1;i<=k;i++)
      		{
      			int a=x[i],b=y[i],c=w[i];
      			if ( a!=1 || b!=1 )
      			{
      				int fx=find(a),fy=find(n+b);
      				int tmp=g[a]^g[n+b]^c;
      				if (fx!=fy)
      				{
      					fa[fy]=fx;
      					g[fy]=tmp;
      				}
      				else if (tmp) return 0;
      			}
      		}
      		int cnt=0;
      		for (int i=1;i<=n+m;i++)
      		{
      			if (i==find(i)) cnt++;
      		}
      		return qpow(2,cnt-1);
      	}
          
          void work()
          {
          	int flag=-1;
          	scanf("%d%d%d",&n,&m,&k);
          	for(int i=1;i<=k;i++)
          	{
          		scanf("%d%d%d",&x[i],&y[i],&w[i]);
          		if(x[i]==1&&y[i]==1)
          		{
          			flag=w[i];
      			}
      			else if(!(x[i]&1)&&!(y[i]&1))
      			{
      				w[i]^=1;
      			}
      		}
      		if(flag!=-1)
      		{
      			printf("%d",work(flag));
      			return ;
      		}
      		else
      		{
      			printf("%d",(work(1)+work(0))%mod);
      			return ;
      		}
      	}
      	 
      }
      
      int main()
      {
      	zzc::work();
      	return 0;
      }
      

  • 相关阅读:
    [20210908]Reverse Shell with Bash.txt
    [20210831]bbed读取数据块6.txt
    自主学习 之 用Python玩转数据
    简单四则运算(PSP)
    永久免费云服务器搭建国内Moon服务加速ZeroTier
    INDEX
    openjdk 8 的 hotspot 源码目录结构
    CentOS 7 编译 openjdk 8
    23
    22
  • 原文地址:https://www.cnblogs.com/youth518/p/13665236.html
Copyright © 2011-2022 走看看