【bzoj 4671】 异或图

题目

神仙题啊神仙题

显然这个东西一脸不可求的样子啊,这种东西我们显然需要搞一个容斥什么的

于是设\(g_i\)表示至少存在\(i\)个联通块(联通块内部的边没有要求,联通块和联通块之间不存在边)的方案数,\(f_i\)表示恰有\(i\)个联通块

\[g_x=\sum_{i=x}^n\begin{Bmatrix}i\\x\end{Bmatrix}f_i\]

即我们对于那些联通块个数多于\(x\)个的情况,可以把这\(i\)个联通快分成\(k\)组,每一组作为一个新的“联通块”,于是后面那个是一个第二类斯特林数

于是根据斯特林反演,有

\[f_x=\sum_{i=x}^n(-1)^{i-x}\begin{bmatrix}i\\x\end{bmatrix}g_i\]

对于这道题我们要求的就是\(f_1\)

\[f_1=\sum_{i=1}^n(-1)^{i-1}(i-1)!g_i\]

现在要做的就是求\(g_i\)了

我们注意到这张图的点数很少,我们甚至可以爆搜一下每个点分到哪一个集合里去,我们就可以扫一遍每一张图,对于一条连接两个不同集合的边,我们把这条边用二进制状态存一下,现在只需要求出有多少个子集异或和为\(0\)就好了

这个问题可以用线性基来解决,结论就是如果有\(x\)个元素不能插入线性基,那么异或和为\(0\)的子集数量就是\(2^x\)个

这个可以这样理解,当有一个元素不能插入线性基的时候,就说明之前有一些元素异或和等于当前这歌元素,我们可以把这个元素和之前那些元素作为一个子集;如果这歌元素是第一个不能插入的元素,那么还有一种方案是空集,否则我们可以把这个元素和上一个不能插入线性基的元素作为一个子集

这样对于每一个不能插入线性基的元素都有两种选择,于是子集个数是\(2^x\)种

代码

#include<cstdio>
#include<cstring>
#define re register
#define LL long long
int m,n,len,t;LL ans,cnt;
char S[1005];
LL fac[15],pw[105],lb[50],g[15],b[66];
int a[15],vis[66][15][15];
inline int ins(LL x) {
    for(re int i=t-1;i>=0;--i)
    if(x>>i&1) {
        if(!lb[i]) {lb[i]=x;return 1;}
        x^=lb[i];
    }
    return 0;
}
void dfs(int x,int now) {
    if(x==n+1) {
        t=0;memset(lb,0,sizeof(lb));
        for(re int k=1;k<=m;k++) {
            b[k]=t=0;
            for(re int i=1;i<=n;i++)
                for(re int j=i+1;j<=n;j++)
                    if(a[i]!=a[j]) b[k]|=(1ll*vis[k][i][j]<<t),t++;
        }
        int tot=0;
        for(re int k=1;k<=m;k++) if(!ins(b[k])) ++tot;
        g[now]+=pw[tot];
        return;
    }
    for(re int i=1;i<=now;i++) a[x]=i,dfs(x+1,now);
    a[x]=now+1;dfs(x+1,now+1);
}
int main() {
    scanf("%d",&m);
    for(re int k=1;k<=m;k++) {
        scanf("%s",S+1);len=strlen(S+1);
        if(!n) {n=1;while(n*(n-1)/2!=len) n++;}
        int now=1;
        for(re int i=1;i<=n;i++)
            for(re int j=i+1;j<=n;j++)
                vis[k][i][j]=S[now]-'0',now++;
    }
    fac[0]=1;pw[0]=1;
    for(re int i=1;i<=m;i++) pw[i]=pw[i-1]+pw[i-1];
    for(re int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i;
    dfs(1,0);
    for(re int i=1;i<=n;i++) ans+=1ll*((i&1)?1:-1)*fac[i-1]*g[i];
    printf("%lld\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/asuldb/p/10940550.html

时间: 2024-07-30 12:53:24

【bzoj 4671】 异或图的相关文章

bzoj 4671: 异或图

4671: 异或图 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 61  Solved: 39[Submit][Status][Discuss] Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中, 否则这条边不在 G 中. 现在给定 s 个结点数相同的图 G1...s, 设 S = {G1, G2, .

bzoj 4671 异或图 —— 容斥+斯特林反演+线性基

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4671 首先,考虑容斥,就是设 \( t[i] \) 表示至少有 \( i \) 个连通块的方案数: 我们希望得到恰好有一个连通块的方案数,但这里不能直接 \( + t[1] - t[2] + t[3] - t[4] ... \),因为每个"恰好 \( i \) 个连通块"的情况并不是在各种 \( t[j] ( j<=i ) \) 中只被算了一次,而是因为标号,被算了 \(

BZOJ 3689: 异或之

二次联通门 : BZOJ 3689: 异或之 /* BZOJ 3689: 异或之 zz题 */ #include <cstdio> #include <iostream> #include <queue> #define rg register struct IO { static const int BUF = 12323233; char p[BUF], *s, *t, e[BUF]; int a[25]; IO () : s (p), t (e) { fread

【XSY2701】异或图 线性基 容斥原理

题目描述 定义两个图\(G_1\)与\(G_2\)的异或图为一个图\(G\),其中图\(G\)的每条边在\(G_1\)与\(G_2\)中出现次数和为\(1\). 给你\(m\)个图,问你这\(m\)个图组成的集合有多少个子集的异或图为一个连通图. \(n\leq 10,m\leq 60\) 题解 考虑枚举图的子集划分,让被划分到不同子集的点之间没有连边,而在同一个子集里面的点可以连通,可以不连通. 可以用高斯消元(线性基)得到满足条件的图的个数.设枚举的子集划分有\(k\)个集合,那么容斥系数就

bzoj4671: 异或图

Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中, 否则这条边不在 G 中. 现在给定 s 个结点数相同的图 G1...s, 设 S = {G1, G2, . . . , Gs}, 请问 S 有多少个子集的异 或为一个连通图? Input 第一行为一个整数s, 表图的个数. 接下来每一个二进制串, 第 i 行的二进制串为 gi, 其中 gi 是原图通过

【BZOJ4671】 异或图

Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中, 否则这条边不在 G 中. 现在给定 s 个结点数相同的图 G1...s, 设 S = {G1, G2, . . . , Gs}, 请问 S 有多少个子集的异 或为一个连通图? Input 第一行为一个整数s, 表图的个数. 接下来每一个二进制串, 第 i 行的二进制串为 gi, 其中 gi 是原图通过

【bzoj4671】异或图(容斥+斯特林反演+线性基)

传送门 题意: 给出\(s,s\leq 60\)张图,每张图都有\(n,n\leq 10\)个点. 现在问有多少个图的子集,满足这些图的边"异或"起来后,这张图为连通图. 思路: 直接考虑判断图的连通不好判断,所以考虑枚举连通块来进行容斥. 定义\(f_i\)表示有\(i\)个连通块的答案,发现连通块这个东西也不好处理,我们只能处理出有多少个连通块,但无法确定每个连通块内部的连通关系. 定义\(g_i\)为至少有\(i\)个连通块的方案数,那么就有关系式:\(\displaystyle

bzoj 1303: [CQOI2009]中位数图 数学

1303: [CQOI2009]中位数图 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1303 Description 给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b.中位数是指把所有元素从小到大排列后,位于中间的数. Input 第一行为两个正整数n和b ,第二行为1~n 的排列. Output 输出一个整数,即中位数为b的

BZOJ 3689 异或 Trie木+堆

标题效果:特定n的数量,这种需求n数22 XOR的值前者k少 首先,我们建立了一个二进制的所有数字Trie木,您可以使用Trie木size域检查出一些其他的数字XOR值首先k少 然后,我们要保持一个堆.其他XOR的整数值首先2增加堆(第一小是自己异或自己.不在题目要求范围内).当取出一个数异或值的第k小后,将第k+1小增加堆 一个异或值会被两个数分别取出一次.所以取出奇数次时输出,取2*k次就可以 时间复杂度O(nlogn) #include<cstdio> #include<cstri