题意
定义两张 n 个点带标号无向图的 xor:结果也是一张 n 个点
的带标号无向图:只包含恰好在一张图中出现的边。
给出 m 张图,问有多少方案选一个子集,xor 起来的图恰好
有 k 个连通块。
O ( B e l l ( n ) ) O(Bell(n)) O(Bell(n))枚举 n n n个点划分为几个块,求块间的边全部不存在的方案数,有 k k k个块的方案数为 f ( k ) f(k) f(k)。
那么考虑一个恰有 p p p个联通块的方案 x x x,对于 f ( k ) f(k) f(k),会计算 x x x的次数是 S 2 ( p , k ) S_2(p,k) S2(p,k),也就是把 p p p个联通块放入 k k k个块中每个块不为空的方案数。
因为
x
n
=
∑
i
=
0
x
S
2
(
n
,
i
)
x
i
‾
x^n = \sum_{i=0}^x S_2(n,i)x^{\underline i}
xn=∑i=0xS2(n,i)xi
这个等式是因为
x
n
x^n
xn的组合意义是把
n
n
n个不同的球放到
x
x
x个不同的盒子中。
我们可以枚举其中
i
i
i个盒子非空即
(
x
i
)
=
x
i
‾
i
!
\binom xi = \frac {x^{\underline i}}{i!}
(ix)=i!xi种方案。
然后把所有的球放入这
i
i
i个不同的(所以要乘
i
!
i!
i!)盒子使得这
i
i
i个盒子没有空的,也即
S
2
(
n
,
i
)
i
!
S_2(n,i)i!
S2(n,i)i!
那么
x
n
=
∑
i
=
0
n
S
2
(
n
,
i
)
x
i
‾
x^n = \sum_{i=0}^n S_2(n,i) x^{\underline i}
xn=∑i=0nS2(n,i)xi
又因为
x
n
‾
=
∑
i
=
0
n
S
1
(
n
,
i
)
x
i
x^{\overline n} = \sum_{i=0}^n S_1(n,i) x^i
xn=∑i=0nS1(n,i)xi
证明,
∏
i
=
0
n
−
1
(
x
+
i
)
\prod_{i=0}^{n-1} (x+i)
∏i=0n−1(x+i)中每个数选
x
x
x,就代表第一类斯特林数中新建了一个圆排列,选
i
i
i就代表插在了之前的
i
i
i个数中的一个的前面。
所以
(
−
x
)
n
‾
=
∑
i
=
0
n
S
1
(
n
,
i
)
(
−
x
)
i
(-x)^{\overline n} = \sum_{i=0}^n S_1(n,i) (-x)^i
(−x)n=∑i=0nS1(n,i)(−x)i
(
−
x
)
n
‾
(
−
1
)
n
=
x
n
‾
=
∑
i
=
0
n
S
1
(
n
,
i
)
(
−
1
)
n
−
i
x
i
(-x)^{\overline n}(-1)^n = x^{\underline n} = \sum_{i=0}^n S_1(n,i)(-1)^{n-i} x^i
(−x)n(−1)n=xn=∑i=0nS1(n,i)(−1)n−ixi
所以
x
n
=
∑
i
=
0
n
S
2
(
n
,
i
)
∑
j
=
0
i
S
1
(
i
,
j
)
(
−
1
)
i
−
j
x
j
x^n = \sum_{i=0}^n S_2(n,i) \sum_{j=0}^iS_1(i,j)(-1)^{i-j}x^j
xn=∑i=0nS2(n,i)∑j=0iS1(i,j)(−1)i−jxj
x
n
=
∑
j
=
0
n
x
j
∑
i
=
j
n
S
2
(
n
,
i
)
S
1
(
i
,
j
)
(
−
1
)
i
−
j
x^n = \sum_{j=0}^n x^j \sum_{i=j}^n S_2(n,i)S_1(i,j)(-1)^{i-j}
xn=∑j=0nxj∑i=jnS2(n,i)S1(i,j)(−1)i−j
由此可得对于固定的
j
j
j
∑
i
=
j
n
S
2
(
n
,
i
)
S
1
(
i
,
j
)
(
−
1
)
i
−
j
=
[
n
=
j
]
\sum_{i=j}^n S_2(n,i)S_1(i,j)(-1)^{i-j} = [n =j]
∑i=jnS2(n,i)S1(i,j)(−1)i−j=[n=j]
回到容斥,
f
(
k
)
f(k)
f(k)会计算恰有
p
p
p个联通块的方案
S
2
(
k
,
p
)
S_2(k,p)
S2(k,p)次,那么我们计算
∑
i
=
1
n
f
(
i
)
S
1
(
i
,
1
)
(
−
1
)
i
−
1
\sum_{i=1}^n f(i)S_1(i,1)(-1)^{i-1}
∑i=1nf(i)S1(i,1)(−1)i−1,根据斯特林反演,每个恰有
p
p
p个联通块的方案的计算权和为
∑
i
=
1
p
S
2
(
p
,
i
)
S
1
(
i
,
1
)
(
−
1
)
i
−
1
=
[
p
=
1
]
\sum_{i=1}^p S_2(p,i)S_1(i,1)(-1)^{i-1} = [p =1]
∑i=1pS2(p,i)S1(i,1)(−1)i−1=[p=1]
所以计算出
f
(
k
)
f(k)
f(k)即可。
f ( k ) f(k) f(k)的计算,对于一定不会出现的边可以列出方程,高斯消元求出自由元个数 r r r, f ( k ) = 2 r f(k) = 2^r f(k)=2r。
A C C o d e \mathcal AC \ Code AC Code
#include<bits/stdc++.h>
#define LL long long
using namespace std;
class Gxor{
LL fac[10],a[55],b[55],ans;
int T,n,c[10],lg[1<<10],dz[100] , cnt[100];
void dfs(int u,int d){
if(u == 0){
int m = 0;
for(int u=0,t=0;u<n;u++)
for(int v=u+1;v<n;v++,t++)
if(c[u] ^ c[v])
a[m++] = b[t];
a[m] = 0;
int r = 0;
for(int i=0;i<T;i++){
if((a[r] >> i & 1) == 0)
for(int j=r+1;j<m;j++)
if(a[j] >> i & 1){
swap(a[r],a[j]);
break;
}
for(int j=r+1;j<m;j++)
if(a[j] >> i & 1)
swap(a[r],a[j]) , a[j] ^= a[r];
if(a[r]>>i&1) r++;
}
ans += fac[d] * (1ll << T >> r);
return ;
}
for(int t=u;t;t=(t-1)&u) if(t & (u & -u)){
for(int s=t;s;s&=(s-1))
c[lg[s&-s]] = lg[u&-u];
dfs(u-t,d+1);
}
}
public:
LL countsubs(vector<string>S){
fac[1] = fac[0] = 1;
for(int i=0;i<10;i++) lg[1<<i] = i;
for(int i=2;i<10;i++) fac[i] = fac[i-1] * (i-1);
for(int i=2;i<10;i+=2) fac[i] = - fac[i];
for(int i=1;i<=9;i++) dz[i * (i-1) / 2] = i;
T = S.size() , n = dz[S[0].size()];
for(int i=0;i<T;i++)
for(int u=0,t=0;u<n;u++)
for(int v=u+1;v<n;v++,t++)
if(S[i][t] == '1')
b[t] |= 1ll << i;
dfs((1<<n)-1,0);
return ans;
}
};