bzoj 2303: [Apio2011]方格染色

传送门

Description

Sam和他的妹妹Sara有一个包含n × m个方格的表格。她们想要将其的每个方格都染成红色或蓝色。
出于个人喜好,他们想要表格中每个2 × 2的方形区域都包含奇数个(1 个或 3 个)红色方格。例如,右图是一个合法的表格染色方案(在打印稿中,深色代表蓝色,浅色代表红色) 。 
可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在Sam和Sara非常生气。不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格仍然满足她们的要求。如果可能的话,满足他们要求的染色方案数有多少呢?

Input

输入的第一行包含三个整数n, m和k,分别代表表格的行数、列数和已被染色的方格数目。 
之后的k行描述已被染色的方格。其中第 i行包含三个整数$x_{i}$, $y_{i}$和$c_{i}$,分别代表第 i 个已被染色的方格的行编号、列编号和颜色。$c_{i}$为 1 表示方格被染成红色,$c_{i}$为 0表示方格被染成蓝色。

Output

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

对于所有的测试数据,$2 ≤ n, m ≤ 10^6,0 ≤ k ≤ 10^6,1 ≤ x_{i} ≤ n,1 ≤ y_{i} ≤ m$。

窝是不会做去看题解的哇……

空灰冰魂这位大佬讲得比较清晰。

思路大约是确定第一行第一列以后其他点都可以确定。

然后对于一组

$$a_{x,y}⊕a_{x-1,y}⊕a_{x,y-1}⊕a_{x-1,y-1}=1$$

它可以化成$$a_{x,y}⊕a_{1,y}⊕a_{x,1}⊕a_{1,1}=f(x,y)$$

f(x,y)=(x&1)|(y&1)

如果有修改在第一行第一列的,我先跑一遍bfs全染出来,再并查集处理那些等于和不等关系。

#include<set>
#include<cstdio>
#include<algorithm>
#define S (!((p[i].x|p[i].y)&1))
#define MN 2100000
using namespace std;

int read_p,read_ca,read_f;
inline int read(){
    read_p=0;read_ca=getchar();read_f=1;
    while(read_ca<‘0‘||read_ca>‘9‘) read_f=read_ca==‘-‘?-1:read_f,read_ca=getchar();
    while(read_ca>=‘0‘&&read_ca<=‘9‘) read_p=read_p*10+read_ca-48,read_ca=getchar();
    return read_p*read_f;
}
struct bi{int y,z,ne;}b[MN];
struct na{int x,y,c;}p[MN];
const int MOD=1e9;
int n,m,k,MMH=0,C[MN],fa[MN],w[MN],l[MN],num;
bool v[MN],gg;
inline void in(int x,int y,int z){b[++num].y=y;b[num].z=z;b[num].ne=l[x];l[x]=num;}
inline void dfs(int x,int c){
    if (C[x]!=c&&C[x]!=-1) gg=1;
    if (v[x]) return;
    v[x]=1;C[x]=c;
    for (int i=l[x];i;i=b[i].ne) dfs(b[i].y,c^b[i].z);
}
int gf(int x){
    if (x==fa[x]) return x;
    int f=fa[x];fa[x]=gf(fa[x]);w[x]^=w[f];
    return fa[x];
}
inline void add(int x,int y,int c){
    int X=gf(x),Y=gf(y);
    if (X==Y){
        if (w[x]^w[y]^c) gg=1;
    }else fa[X]=Y,w[X]=c^w[x]^w[y];
    //printf("%d %d %d %d %d %d %d %d\n",x,y,w[x],w[y],X,Y,c,gg);
}
inline void work(int x){
    num=0;gg=0;
    for (int i=1;i<=n+m-1;i++) C[i]=-1,fa[i]=i,l[i]=v[i]=0,w[i]=0;
    for (int i=1;i<=k;i++)
    if (p[i].x==1&&p[i].y==1){if (p[i].c!=x) return;}
    else if (p[i].x==1){if (C[p[i].y]==(p[i].c^1))gg=1;C[p[i].y]=p[i].c;}
    else if (p[i].y==1){if (C[p[i].x-1+m]==(p[i].c^1))gg=1;C[p[i].x-1+m]=p[i].c;}
    else in(p[i].y,p[i].x-1+m,p[i].c^x^S),in(p[i].x-1+m,p[i].y,p[i].c^x^S);

    for (int i=1;i<=n+m-1;i++)
    if (C[i]!=-1&&!v[i]) dfs(i,C[i]);

    for (int i=1;i<=k;i++)
    if (p[i].x!=1&&p[i].y!=1) add(p[i].y,p[i].x-1+m,p[i].c^x^S)/*,printf("%d %d %d\n",p[i].y,p[i].x-1+m,p[i].c^x^S)*/;

    if (gg) return;

    int mmh=1;
    for (int i=2;i<=n+m-1;i++)
    if (C[i]==-1&&fa[i]==i) mmh+=mmh,mmh-=mmh>=MOD?MOD:0;
    MMH+=mmh;MMH-=MMH>=MOD?MOD:0;
    //printf("%d %d\n",x,mmh);
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=k;i++) p[i].x=read(),p[i].y=read(),p[i].c=read();
    work(0);work(1);
    printf("%d\n",MMH);
}

时间: 2024-10-14 05:38:57

bzoj 2303: [Apio2011]方格染色的相关文章

BZOJ 2303: [Apio2011]方格染色 题解

题目大意: 有n*m的方格,中间的数要么是1,要么是0,要求任意2*2的方格中的数异或和为1.已知一部分格子中的数,求合法的填数的方案数. 思路: 由题意得:a[i][j]^a[i][j+1]^a[i+1][j]^a[i+1][j+1]=1,令这个式子为S(i,j),那么对于某一格(i,j),我们把S(1,1)...S(i,j)异或起来,则可得当i,j均为偶数时a[1][1]^a[i][1]^a[1][j]^a[i][j]=1(于是为了方便先预处理一下),否则a[1][1]^a[i][1]^a[

BZOJ2303: [Apio2011]方格染色

2303: [Apio2011]方格染色 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1927  Solved: 744[Submit][Status][Discuss] Description Sam和他的妹妹Sara有一个包含n × m个方格的 表格.她们想要将其的每个方格都染成红色或蓝色. 出于个人喜好,他们想要表格中每个2 ×   2的方形区 域都包含奇数个(1 个或 3 个)红色方格.例如,右 图是一个合法的表格染色方案(在打印稿中,

BZOJ_2303_[Apio2011]方格染色 _并查集

Description Sam和他的妹妹Sara有一个包含n × m个方格的 表格.她们想要将其的每个方格都染成红色或蓝色. 出于个人喜好,他们想要表格中每个2 ×   2的方形区 域都包含奇数个(1 个或 3 个)红色方格.例如,右 图是一个合法的表格染色方案(在打印稿中,深色代 表蓝色,浅色代表红色) . 可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在Sam和Sara 非常生气.不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格 仍然满足她们的要求.如果可能的话,满足他们

【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,

BZOJ 2303 方格染色

首先考虑四个格子异或值为1. 然后(重点)发现每个格子的值只和最上面,最左边,和(1,1)的格子的颜色有关. 枚举(1,1)的颜色,联立方程,可以将未知数减少,那么并查集可做. 最后算答案的时候,有些连通块颜色确定,有些不确定,不确定的*2即可. 这题要注意细节!其实一开始的思路最不好想. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define max

【BZOJ2303】【Apio2011】方格染色 异或方程+并查集

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45081583"); } 题解: 首先我们发现对于 ai,j 有下列式子: ai,j xor ai+1,j xor ai,j+1 xor ai+1,j+1==1 然后推导得到对于 ai,j 有下列式子: a1,1 xor a1,j x

bzoj 4033: [HAOI2015]树上染色

4033: [HAOI2015]树上染色 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1886  Solved: 805 Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并 将其他的N-K个点染成白色.将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的收益. 问收益最大值是多少. Input 第一行两个整数N,K. 接下来N-1行每行三个正整数fr

bzoj 1006 弦图染色

给定一个弦图,问最少染色数. 对于弦图的一个完美消去序列,从后往前染色,每次染可以染的最小编号的颜色,由完美消去序列的定义,序列任一后缀的点的导出子图中,由该后缀第一个元素及其邻接点导出的子图一定是完全图,所以,序列中某一元素染的颜色编号是该完全图的大小.所以最小染色数小于等于最大团的点数,而显然前者又大于等于后者,故弦图的最小染色数等于最大团的大小. 1 /************************************************************** 2 Prob

[BZOJ 2243] [SDOI 2011] 染色

题目链接:BZOJ - 2243 题目分析 树链剖分...写了200+行...Debug了整整一天+... 静态读代码读了 5 遍 ,没发现错误,自己做小数据也过了. 提交之后全 WA . ————————————— 杯具的分割线 ————————————————— 然后看了别人代码..然后发现.. 我写线段树区间修改竟然没打标记!!!!直接就修改上了!!!最裸的线段树都不会写了!!! Warning!Warning!Warning! 代码 #include <iostream> #inclu