【TC SRM 670】Gxor(斯特林反演,容斥原理)

题意
定义两张 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=0n1(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)nixi

所以 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)ijxj
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=0nxji=jnS2(n,i)S1(i,j)(1)ij
由此可得对于固定的 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)ij=[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)i1,根据斯特林反演,每个恰有 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)i1=[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;
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值