• [APIO2011]方格染色


    题目描述

    Sam和他的妹妹Sara有一个包含n*m个方格的表格。他们想要将其中的每个方格都染成红色或蓝色。出于个人喜好,他们想要表格中每个2*2的方形区域都包含奇数个(1个或3个)红色方格。例如,下面是一个合法的表格染色方案(R代表红色,B代表蓝色,原来是张图):

    B B R B R

    R B B B B

    R R B R B

    可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在Sam和Sara非常生气。不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格依然满足他们的要求。如果可能的话,满足他们要求的染色方案数有多少呢?

    输入输出格式

    输入格式:

    输入的第一行包含三个整数n,m和k,分别代表表格的行数,列数和已被染色的方格数目。

    之后的k行描述已被染色的方格。其中第i行包含三个整数x[i],y[i]和c[i],分表代表第i个已被染色的方格的行编号、列编号和颜色。c[i]为1表示方格被染成红色,c[i]为0表示方格被染成蓝色。

    输出格式:

    输出一个整数,表示可能的染色方案数W模10^9得到的值。(也就是说,如果W大于等于10^9,则输出W被10^9除所得到的余数)。

    输入输出样例

    输入样例#1: 复制
    3 4 3
    2 2 1
    1 2 0
    2 3 1
    输出样例#1: 复制
    8

    说明

    对于20%的测试数据,n,m<=5,k<=5。

    对于50%的测试数据,n,m<=5000,k<=25。

    对于100%的测试数据,2<=n,m<=10^5,0<=k<=10^5,1<=x[i]<=n,1<=y[i]<=m。

    首先发现,如果我们把蓝色看作1,把红色看作0,那么对于每一个格子a(i,j),都有:a(i,j)^a(i+1,j)^a(i,j+1)^a(i+1,j+1)=1

    那么只要第一列和第一行确定了如何染色,整个表格的染色就确定了

    如果(x,y)的值为1/0那么第一行和第一列的值就会有限制

    如果(x,y)都是偶数,那么2*2的矩形总数为奇数,异或和为1

    而且除了(1,1),(x,1),(1,y),(x,y)以外其它格子都异或了2次

    所以a(1,1)^a(x,1)^a(1,y)^a(x,y)=1

    即a(1,1)^a(x,1)^a(1,y)=a(x,y)^1

    否则就是a(1,1)^a(x,1)^a(1,y)=a(x,y)

    所以讨论a(1,1)的值可以得到a(x,1)和a(1,y)的值的异或关系

    也就是说,存在下列关系

    相同,不同,关系不确定,前两种都是连通,只不过关系不同

    所以用带权并查集维护

    d[x]表示x与他的根是相同还是不同

    特别注意当确定了第一行/列的值时

    那么该联通块的值就确定了

    pd[x]表示x的值,不确定为-1

    如果中间冲突返回0

    最后结果是2^不确定值的联通块数

    a(1,1)=1的情况吧所有a(x,y)^1就行了

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 typedef long long lol;
     8 int set[200001],d[200001],pd[200001],n,m,k,x[200001],y[200001],w[200001],Mod=1e9;
     9 int find(int x)
    10 {
    11   if (set[x]==x) return x;
    12   int t=set[x];
    13   set[x]=find(set[x]);
    14   d[x]=(d[x]+d[t])%2;
    15   return set[x];
    16 }
    17 int work0()
    18 {int i;
    19   lol ans;
    20   int p,q,t;
    21   for (i=1;i<=n+m;i++)
    22     set[i]=i,d[i]=0,pd[i]=-1;
    23   pd[1]=0;
    24   set[n+1]=1;
    25   for (i=1;i<=k;i++)
    26     {
    27       if (x[i]==1&&y[i]==1) continue;
    28       if (x[i]==1||y[i]==1)
    29     {
    30       if (y[i]==1) p=find(x[i]),t=x[i];
    31       else p=find(y[i]+n),t=y[i]+n;
    32       if (pd[p]==-1) pd[p]=d[t]^w[i];
    33       else if (pd[p]!=(d[t]^w[i])) return 0;
    34       continue;
    35     }
    36       int p=find(x[i]),q=find(y[i]+n);
    37       if (p!=q)
    38     {
    39       set[p]=q;
    40       d[p]=d[y[i]+n]^d[x[i]]^w[i];
    41       if (pd[p]!=-1&&pd[q]!=-1&&(pd[p]^d[p])!=pd[q]) return 0;
    42       if (pd[p]!=-1&&pd[q]==-1)
    43         pd[q]=d[p]^pd[p],pd[p]=-1;
    44     }
    45       else
    46     {
    47       if ((d[x[i]]^d[y[i]+n]^w[i])==1) return 0;
    48     }
    49     }
    50   ans=1;
    51   for (i=1;i<=n+m;i++)
    52     if (find(i)==i&&pd[i]==-1) ans=ans*2%Mod;
    53   return ans;
    54 }
    55 int main()
    56 {lol ans=0;
    57   int i,flag=-1;
    58   cin>>n>>m>>k;
    59   for (i=1;i<=k;i++)
    60     {
    61       scanf("%d%d%d",&x[i],&y[i],&w[i]);
    62       if (x[i]==1&&y[i]==1) flag=w[i];
    63       if (!(x[i]&1)&&!(y[i]&1)) w[i]^=1;
    64     }
    65   if (flag==-1||flag==0) ans+=work0();
    66   if (flag==-1||flag==1)
    67     {
    68       for (i=1;i<=k;i++)
    69     w[i]^=1;
    70       ans+=work0();
    71       ans%=Mod;
    72     }
    73   cout<<ans;
    74 }
  • 相关阅读:
    交换变量方法总结
    Java Object Model(一)
    Git命令文本手册
    移动端浏览器touch事件的研究总结
    jQuery中的end()方法
    AngularJs开发——控制器间的通信
    网站收藏
    HTTP Content-type 对照表
    ViewData和ViewBag的那些事
    jQuery选择器
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8909095.html
Copyright © 2020-2023  润新知