• BZOJ4671 异或图


    Description

    定义两个结点数相同的图 $G_1$ 与图 $G_2$ 的异或为一个新的图 $G$, 其中如果 $(u,v)$ 在 $G_1$ 与$G_2$ 中的出现次数之和为 $1$, 那么边 $(u,v)$ 在 $G$ 中, 否则这条边不在 $G$ 中.
    现在给定 $s$ 个结点数相同的图 $G_{1 cdots s}$, 设 $S={G_1,G_2,cdots,G_s}$, 请问 $S$ 有多少个子集的异或为一个连通图?

    Solution

    考虑类似容斥的做法,计算图不连通的情况数

    设$f_i$表示将图分为$i$个部分,这$i$个部分之间没有连边,每个部分内部不做要求的方案数,$g_i$表示图分为恰好$i$个连通块的方案数

    那么有

    $$f_i=sum _{j=i}^n egin{Bmatrix}j \i end{Bmatrix}g_i$$

    斯特林反演:

    $$displaystyle f(n)=sum_{k=0}^n egin{Bmatrix}n\k end{Bmatrix}g(k)Longleftrightarrow g(n)=sum_{k=0}^n(-1)^{n-k}egin {bmatrix} n\k end{bmatrix}f(k)$$

    可得(虽然是向上枚举但是应该也对)

    $$g_i=sum _{j=i}^n (-1)^{j-i}egin{bmatrix}j \i end{bmatrix}f_j$$

    题中要求的是$g_1=sum _{i=1}^n (-1)^{i-1}(i-1)!f_i$

    问题转化为求$f_i$

    可以想到对于确定的分组,每个部分之间的边在一个图中存在状态是确定的

    所以可以用线性基,向其中加入01串,每个串表示对应的图中部分之间连边是否存在

    那么就是求这些01串可以异或出0的方案数,设线性基中数的个数为$c$

    答案为$2^{s-c}$

    在$Bell(n)$复杂度内搜索即可

    在将数加入线性基时发现的:将一个01矩阵每一行看作一个数和每一列看作一个数加入线性基,线性基中数的个数相等

    最后的解释是转置矩阵的秩等于原矩阵的秩

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int s,len,n,tot,g[15];
    long long fac[15]={1},base[70],temp,ans,map[65][15][15],b[65];
    char str[105];
    inline int read()
    {
        int f=1,w=0;
        char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
        return f*w;
    }
    void dfs(int k,int top)
    {
        if(k==n)
        {
            memset(base,0,sizeof(base));
            for(int i=1;i<=s;i++)
            {
                temp=0;
                int cnt=0;
                for(int j=1;j<=n;j++) for(int l=j+1;l<=n;l++) if(g[j]!=g[l]) temp|=map[i][j][l]<<cnt,++cnt;
                for(int j=50;~j;j--) if(temp>>j&1)
                    if(base[j]) temp^=base[j];
                    else
                    {
                        base[j]=temp;break;
                    }
            }
            int cnt=0;
            for(int l=0;l<50;l++) cnt+=(base[l]>0);
            if(top&1) ans+=(1ll<<s>>cnt)*fac[top-1];
            else ans-=(1ll<<s>>cnt)*fac[top-1];
            return;
        }
        for(int i=1;i<=top+1;i++) g[k+1]=i,dfs(k+1,max(top,g[k+1]));
    }
    int main()
    {
        s=read();
        for(int i=1;i<=s;i++)
        {
            scanf("%s",str),len=strlen(str),n=(1+sqrt(1+8*len))/2,tot=0;
            for(int j=1;j<=n;j++) for(int k=j+1;k<=n;k++) map[i][j][k]=str[tot++]-'0';
        }
        for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i;
        dfs(0,0);
        printf("%lld
    ",ans);
        return 0;
    }
    异或图
  • 相关阅读:
    第5章 继承
    第4章 对象和类
    第3章 java的基本程序设计结构
    Java读写properties格式配置文件
    Net学习日记_三层_2
    Net学习日记_三层_1_登录页面总结篇_残缺版
    Net学习日记_三层_1
    Net学习日记_SQL进阶_2
    Net学习日记_SQL进阶_1
    Net学习日记_ADO.Net_3_案例
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14090087.html
Copyright © 2020-2023  润新知