【bzoj 2303】【Apio2011】方格染色
题目:
http://www.lydsy.com/JudgeOnline/problem.php?id=2303
题解:
很神奇的思路,膜一发大佬http://www.cnblogs.com/HHshy/p/5840018.html#undefined
设S(i,j)=a[i][j]^a[i+1][j]^a[i][j+1]^a[i+1][j+1]。那么将S(1,1)^S(1,2)^...^S(1,j)^S(2,1)^...^S(2,j)^.....^S(i,j)展开,对于i相同的一行(如S(1,1)^S(1,2)^...^S(1,j)),我们可以先然看出其结果为开头的a[i][1]^a[i][j],同时其在下一层的异或结果也是a[i+1][1]^a[i+1][j],那么再把每一行合并,最终我们得到此式的化简:a[1][1]^a[i+1][1]^a[1][j+1]^a[i+1][j+1],然后当i,j均为奇数时,我们得知a[1][1]^a[i+1][1]^a[1][j+1]^a[i+1][j+1]==1,否则为0,再把那个+1缩掉,即:((i|j)&1)==0时,a[1][1]^a[i][1]^a[1][j]^a[i][j]==1,否则为0.设a[1][1]^a[i][1]^a[1][j]^a[i][j]为z,再移一下项,我们得到z^a[1][1]^a[i][j]==a[i][1]^a[1][j],然后枚举a[1][1]的值,再用并查集把有关的a[i][1]与a[1][j]连接起来,判断是否会出现矛盾,如果没有矛盾,我们就得到了一部分答案。最后把两个a[1][1]值的贡献加和即可。
1 #include<cstdio> 2 const int N=(int )1e6+5,mod=(int) 1e9; 3 inline int read(void ){ 4 int s=0;char ch=getchar(); 5 while(ch<'0'||ch>'9') ch=getchar(); 6 while(ch>='0'&&ch<='9') s=s*10+(ch^48),ch=getchar(); 7 return s; 8 } 9 10 int n,m,k; 11 int x[N],y[N],z[N],g[N],f[N]; 12 inline int find(int x){ 13 if(x==f[x]) return x; 14 int t=find(f[x]);g[x]^=g[f[x]]; 15 return f[x]=t; 16 } 17 inline int solve() 18 { 19 for(int i=1;i<=n+m;i++) f[i]=i,g[i]=0; 20 f[n+1]=1; 21 for (int i=1;i<=k;i++) 22 { 23 int u=find(x[i]),v=find(y[i]+n),t=g[x[i]]^g[y[i]+n]^z[i]; 24 if (u!=v) f[u]=v,g[u]=t; 25 else if (t) return 0; 26 } 27 int sum=0; 28 for (int i=1;i<=n+m;i++) 29 if (f[i]==i) 30 if (!sum) sum=1; 31 else { 32 sum<<=1; 33 sum-=mod*(sum>mod); 34 } 35 return sum; 36 } 37 int main(){ 38 bool e[2]={1,1}; 39 n=read(),m=read(),k=read(); 40 for(int i=1;i<=k;i++){ 41 x[i]=read(),y[i]=read(),z[i]=read(); 42 if(!((x[i]^1)|(y[i]^1))){ 43 e[z[i]]=0,i--,k--;continue; 44 } 45 if(!((x[i]|y[i])&1)) z[i]^=1; 46 } 47 int ans=0; 48 if(e[1]) ans=solve(); 49 if(e[0]){ 50 for(int i=1;i<=k;i++) 51 if((x[i]^1)&&(y[i]^1)) z[i]^=1; 52 ans+=solve(); 53 ans-=(ans>mod)*mod; 54 } 55 printf("%d\n",ans); 56 }
//承认抄代码。。
没有什么不可能。