bzoj 4671: 异或图 容斥+斯特林反演+线性基
2018-04-03 09:20
309 查看
题意
定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中, 否则这条边不在 G 中.
现在给定 s 个结点数相同的图 G1…s, 设 S = {G1, G2, … , Gs}, 请问 S 有多少个子集的异
或为一个连通图?
分析
我们有一个想法,就是枚举子图的子集,然后再来搞,这样显然不行,因为m有60这么大另外一个方向,我们从n开始入手,用贝尔数的时间(其实就是第二类斯特林数的一行的和)来进行把这些点划分,然后同一个集合里面的点可以有边也可以没有,不同集合一定没边
至于算方案数,我们可以把每一条不在集合的边变成一个二进制位,有边则为1,没有则为0,插入线性基,看看自由元个数,假设为cnt,那么答案就贡献2cnt
1a7a6
2cnt
考虑这个方案数其实代表什么,代表的就是一些子图子集的划分,变成这样的一个至少为m联通块的方案数
考虑一种子图子集的划分,会被算到的次数是
∑i=1mS(m,i)∑i=1mS(m,i)
之后另外一个现实,有一个容斥系数为(−1)m−1(m−1)!(−1)m−1(m−1)!
就可以算出联通块个数恰好为n=1的情况
下面简单证明一下:
∑m=1n(−1)m−1(m−1)!S(n,m)=∑m=1n−1(−1)m−1(m−1)!(S(n−1,m−1)+mS(n−1,m))+(−1)n−1(n−1)!=∑m=1n−1(−1)m−1(m−1)!S(n−1,m−1)+∑m=1n−1(−1)m−1m!S(n−1,m)+(−1)n−1(n−1)!=∑m=1n−1(−1)m−1(m−1)!S(n−1,m−1)+∑m=1n−2(−1)m−1m!S(n−1,m)=0[n>1](1)(1)∑m=1n(−1)m−1(m−1)!S(n,m)=∑m=1n−1(−1)m−1(m−1)!(S(n−1,m−1)+mS(n−1,m))+(−1)n−1(n−1)!=∑m=1n−1(−1)m−1(m−1)!S(n−1,m−1)+∑m=1n−1(−1)m−1m!S(n−1,m)+(−1)n−1(n−1)!=∑m=1n−1(−1)m−1(m−1)!S(n−1,m−1)+∑m=1n−2(−1)m−1m!S(n−1,m)=0[n>1]
显然只有当n=1时上式=1
然后就没了,这个东西叫做斯特林反演?
还要卡卡常
代码
#include <bits/stdc++.h> #define ll long long #define bin(i) (1ll<<(i)) #define c(i,j) (fac[(i)] * inv[(j)] % mod * inv[(i) - (j)] % mod) using namespace std; const int N = 65; inline int read() { char ch=getchar(); int p=0; int f=1; while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();} return p*f; } int s; char ss[12*12]; int n; bool v [12][12]; int bel[12]; int fac[12]; int cnt; ll b ,ans = 0; void dfs(ll x,ll y) { if(x>n) { cnt = 0; for(int k=1;k<=s;k++) { int l=0; ll t=0; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(bel[i] != bel[j]) t|=bin(l) * v[k][i][j],l++; // printf("%lld\n",t); for(int i=1;i<=cnt;i++) if((t^b[i]) < t) t^=b[i]; if(t) b[++cnt] = t; } ans = ans + bin(s-cnt) * ((y&1) ? 1 : (-1)) * fac[y-1]; // printf("%lld\n",bin(s-cnt) * ((y&1) ? 1 : (-1)) * fac[y-1]); // printf("%lld %lld %lld\n",x,y,bin(s-cnt) * ((y&1) ? 1 : (-1)) * fac[y-1]); return ; } for(int i=1;i<=y+1;i++) bel[x] = i,dfs(x+1,y+(i>y)); } int main() { s = read(); for(int i=1;i<=s;i++) { scanf("%s",ss+1); int len = strlen(ss + 1); for(int j=1;j<=10;j++) if(j*(j-1)/2 == len){n=j; break;} int l=1; for(int j=1;j<=n;j++) for(int k=j+1;k<=n;k++,l++) if(ss[l]=='1') v[i][j][k] = v[i][k][j] = 1; } fac[0] = 1; for(int i=1;i<=n;i++) fac[i] = fac[i-1] * i ; dfs(1,0); return printf("%lld\n",ans),0; }
相关文章推荐
- [BZOJ4671]异或图 线性基+stirling反演
- BZOJ 4671 异或图 | 线性基 容斥 DFS
- BZOJ2115 线性基 对于异或环的处理
- BZOJ2115 线性基 对于异或环的处理
- BZOJ2115 线性基 对于异或环的处理
- BZOJ 2844 异或线性基(HDU3949 升级版
- BZOJ2115 线性基 对于异或环的处理
- 【BZOJ】4671: 异或图
- BZOJ2115 线性基 对于异或环的处理
- 【BZOJ2460】元素(BJOI2011)-异或线性基+贪心
- BZOJ2115 线性基 对于异或环的处理
- BZOJ2115 线性基 对于异或环的处理
- BZOJ 2115: [Wc2011] Xor (dfs + gauss 线性基 异或最长路)
- bzoj 4671: 异或图
- BZOJ2115 线性基 对于异或环的处理
- BZOJ2115 线性基 对于异或环的处理
- [bzoj4671]异或图
- BZOJ2115 线性基 对于异或环的处理
- [BZOJ 4671]异或图
- BZOJ2115 线性基 对于异或环的处理