• [APIO2011] 方格染色


    一、题目

    点此看题

    二、解法

    其实这题相当于给了若干个等式让你求解的个数,思路是我们找出自由变元

    然后这个问题的背景又是矩阵,那么我们自由变元通常出现在边界上。

    不难发现我们确定第一行和第一列之后整个矩阵就确定了,那么第一行第一列就是自由变元。

    再考虑这道题给定了几个位置必须染某颜色,假设是 ((x,y)) 必须染颜色 (c),我们可以通过取 ([1,1,x,y]) 这个矩阵中所有的 (2 imes 2) 的小矩形来列方程,发现除了 ((1,1),(1,x),(1,y),(x,y)) 的元素都被消掉了,那么有 (c(1,1)oplus c(1,x)oplus c(1,y)oplus c(x,y)=[x\%2=0&y\%2=0])

    那么我们可以枚举 ((1,1)) 的颜色,就转化成了 ((1,x))((1,y)) 的关系,这可以用带权并查集维护。

    但是 (x=1/y=1) 也是有可能的,这时候我们在每个并查集的根上打个标记,表示根的颜色是否确定。最后的答案是二的根不定颜色的连通块个数次方。

    三、总结

    要有解方程的思想,虽然你不用真的把他解出来,列方程是表示关系的重要方式。

    #include <cstdio>
    const int M = 200005;
    const int MOD = 1e9;
    #define int long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,k,fl,ans,fa[M],x[M],y[M],b[M],c[M],w[M];
    int find(int x)
    {
    	if(x!=fa[x])
    	{
    		int t=fa[x];
    		fa[x]=find(fa[x]);
    		w[x]^=w[t];
    	}
    	return fa[x];
    }
    int work()
    {
    	int res=1;
    	for(int i=1;i<=n+m;i++)
    		fa[i]=i,b[i]=-1,w[i]=0;
    	fa[n+1]=1;b[1]=0;
    	for(int i=1;i<=k;i++)
    	{
    		if(x[i]==1 && y[i]==1) continue;
    		if(x[i]==1 || y[i]==1)
    		{
    			int u=x[i]==1?y[i]+n:x[i],t=find(u);
    			if(b[t]==-1) b[t]=w[u]^c[i];
    			else if(b[t]!=w[u]^c[i]) return 0;
    			continue;
    		}
    		int u=find(x[i]),v=find(y[i]+n);
    		if(u==v)
    		{
    			if(w[x[i]]^w[y[i]+n]!=c[i]) return 0;
    			continue;
    		}
    		fa[u]=v;w[u]=w[x[i]]^w[y[i]+n]^c[i];
    		if(b[u]!=-1 && b[v]!=-1)
    			{if(b[u]^b[v]!=w[u]) return 0;}
    		else if(b[u]!=-1) b[v]=b[u]^w[u];
    	}
    	for(int i=2;i<=n+m;i++)
    		if(i==find(i) && b[i]==-1)
    			res=res*2%MOD;
    	return res;
    }
    signed main()
    {
    	n=read();m=read();k=read();fl=-1;
    	for(int i=1;i<=k;i++)
    	{
    		x[i]=read();y[i]=read();c[i]=read();
    		if(x[i]==1 && y[i]==1) fl=c[i];
    		if(x[i]%2==0 && y[i]%2==0) c[i]^=1;
    	}
    	if(fl==-1 || fl==0) ans+=work();
    	if(fl==-1 || fl==1)
    	{
    		for(int i=1;i<=k;i++) c[i]^=1;
    		ans+=work();
    	}
    	printf("%lld
    ",ans%MOD);
    }
    
  • 相关阅读:
    MultipartFile(文件的上传)
    JSONObject.fromObject--JSON与对象的转换
    Map集合与转化
    java读取excel文件
    Java中的Arrays类使用详解
    Arrays 类的 binarySearch() 数组查询方法详解
    JDK8 特性详解
    关于Java堆、栈和常量池的详解
    深入java final关键字
    杯酒人生
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15154025.html
Copyright © 2020-2023  润新知