zoukankan      html  css  js  c++  java
  • BZOJ 2303: [Apio2011]方格染色 [并查集 数学!]

    题意:

    $n*m:n,m le 10^6$的网格,每个$2 imes 2$的方格必须有1个或3个涂成红色,其余涂成蓝色

    有一些方格已经有颜色

    求方案数


    太神了!!!花我三节课

    首先想了一下只有两行,发现可以直接$f[i][3] DP$出来,每一列放的方案只与上一列有关

    如果有多行呢,我们可以把上一列放的状态状压$f[i][s]$,然后枚举转移

    复杂度爆炸

    好,看一眼题解

    woc题解说的些什么东西根本看不懂,还是自己想吧

    发现,貌似一个状态只有两个后继状态唉,就是说这一列的右面一列只有两种放法是合法的

    数学归纳法证一下,两行的情况每种列的放法有两个后继,设n行成立,那么n+1行的下一列选或不选就已经确定了...好像成立唉!

    并且这两个后继还是每个位置都相反的!

    总算看明白题解那句:

    如果确定了第一行,接下来的每一行只会是 1.上一行所有奇数列异或1后得到 2.上一行所有偶数列异或1后得到 (这里把之前的行列倒换了)

    其实可以直观理解,因为要保证是奇性啊

    这样的话,不考虑已经涂色的,方案数就是第一行的方案数*(行数-1)$2^{n+m-1}$了

    考虑涂色!

    首先,每个有涂色的行两个后继状态只有一个合法了

    再考虑这一行的涂色对第一行的影响,如果有一行两个位置$x,y$已经涂色,因为只有那两种变换所以:

    $1. x,y同奇偶,每行都必须同色$

    $2. x,y异奇偶,跟这一行同奇偶的行必须同色,异奇偶的行必须异色$

    用个种类并查集就可以判断无解了!

    方案数?把有关系限制的列连起来,求连通块数就行了 

    注意第一行如果有已经涂色的,颜色就直接确定了而不是同色或者异色,所以包含他们的连通块不能再考虑

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    using namespace std;
    #define pii pair<int, int>
    #define MP make_pair
    #define fir first
    #define sec second
    const int N=1e6+5, P=1e9;
    typedef long long ll;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    int n, m, k, c[N], p, x, y;
    struct meow{int r, c;}t;
    vector<meow> q[N];
    int fa[N];
    int find(int x) {return x==fa[x] ? x : fa[x]=find(fa[x]);}
    struct UFS{
        int fa[N], val[N];
        int find(int x) {
            if(x == fa[x]) return x;
            int root = find(fa[x]);
            val[x] ^= val[fa[x]];
            return fa[x] = root;
        }
        bool Union(int x, int y, int p) {
            int f1 = find(x), f2 = find(y);
            if(f1 != f2) {
                fa[f1] = f2;
                val[f1] = val[x]^val[y]^p;
            } else if((val[x]^val[y]) != p) return false;
            return true;
        }
    }F;
    int fix[N], mark[N];
    int Pow(ll a, int b) {
        ll ans=1;
        for(; b; b>>=1, a=a*a%P) 
            if(b&1) ans=ans*a%P;
        return ans;
    }
    int main() {
        freopen("in","r",stdin);
        n=read(); m=read(); k=read();
        for(int i=1; i<=k; i++) {
            x=read(), t.r=read(), t.c=read(), q[x].push_back(t);
            mark[x] = 1;
            if(x == 1) fix[t.r] = 1;
        }
        for(int i=1; i<=m; i++) fa[i] = F.fa[i] = i;
        for(int i=1; i<=n; i++)
            for(int j=1; j<(int)q[i].size(); j++) {
                int a = q[i][j-1].c, b = q[i][j].c, x=q[i][j-1].r, y=q[i][j].r;
                int f1 = find(x), f2 = find(y);
                fa[f1] = f2;
                if(fix[f1]) fix[f2] = 1;
                int p = a^b; if((x&1) != (y&1)) p ^= (i-1)&1;
                if(!F.Union(x, y, p)) {puts("0"); return 0;}
            }
        int ans = 0;
        for(int i=2; i<=n; i++) ans += !mark[i];
        for(int i=1; i<=m; i++) if(fa[i]==i && !fix[i]) ans++;
        printf("%d
    ", Pow(2, ans));
    }
  • 相关阅读:
    帆软—ORA-28040: No matching authentication protocol;
    Vmware虚拟机三种网络模式详解(转)
    ABAP—权限对象设计及权限检查
    ABAP—SM30维护表时提示“客户XXX有“不可修改”的状态”
    ABAP—SM维护表及标题“+”处理
    NC—语义模型调用存储过程(转)
    ABAP—多页签SHEET、选项参数或block隐藏
    oracle—聚合函数(max、min、avg、sum、count)
    oracle—decode、nvl、rownum、like、all、any使用
    从零开始的react入门教程(七),react中的状态提升,我们为什么需要使用redux
  • 原文地址:https://www.cnblogs.com/candy99/p/6595028.html
Copyright © 2011-2022 走看看