zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",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
    ",MMH);
    }
    View Code
  • 相关阅读:
    微服务实战(二):使用API Gateway
    微服务实战(一):微服务架构的优势与不足
    在WIN7、WIN10操作系统用WebDAV映射网络驱动器需要的操作
    docker开机启动和docker-compose开机启动执行相应的各个docker容器
    /etc/rc.d/init.d自启动程序说明
    C# 通过反射实现对象映射:将2个属性相近的对象相互转换
    添加windows右键菜单:使用exe应用程序打开文件/文件夹
    .NET5 MVC Program.cs 笔记
    前端 JS 正则表达式积累
    VS Code 快捷键
  • 原文地址:https://www.cnblogs.com/Enceladus/p/7125601.html
Copyright © 2011-2022 走看看