bzoj4671 异或图(斯特林反演,线性基)

bzoj4671 异或图(斯特林反演,线性基)

祭奠天国的bzoj。

题解时间

首先考虑类似于容斥的东西。

设 $ f_{ i } $ 为至少有 $ i $ 个连通块的方案数, $ g_{ i } $ 为正好有 $ i $ 个连通块的方案数。

那么有

\[f_{ m } = \sum\limits_{ i = m }^{n} \begin{Bmatrix} i \\ m \end{Bmatrix} g_{ i } \]

斯特林反演就有

\[g_{ 1 } = \sum\limits_{ i = 1 }^{ n } (-1)^{ i - 1 } \begin{bmatrix} i \\ 1 \end{bmatrix} f_{ i } \]

其中

\[\begin{bmatrix} i \\ 1 \end{bmatrix} = ( i - 1 )! \]

那么考虑求 $ f_{ i } $ 。

枚举所有可能的子集划分,复杂度为 $ Bell(n) $ ,

对于每个划分,要保证划分之间的边全部不存在,

由此得出异或方程组,设秩为 $ c $ ,则对答案贡献为 $ 2^{ s - c } $ 。

线性基解决。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long lint;
struct pat{int x,y;pat(int x=0,int y=0):x(x),y(y){}bool operator<(const pat &p)const{return x==p.x?y<p.y:x<p.x;}};
template<typename TP>inline void read(TP &tar)
{
	TP ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){ret=ret*10+(ch-'0');ch=getchar();}
	tar=ret*f;
}
template<typename TP,typename... Args>inline void read(TP& t,Args&... args){read(t),read(args...);}
namespace RKK
{
const int N=12,M=62;
int n,m,len;lint ans;
char str[114];
bool mp[M][N][N];
lint fac[N];
int bl[N];
lint b[M];
void dfs(int x,int cnt)
{
	if(x>n)
	{
		int s=0;
		for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)if(bl[i]!=bl[j])
		{
			lint val=0;
			for(int k=1;k<=m;k++)if(mp[k][i][j]) val|=(1ll<<(k-1));
			for(int k=1;k<=s;k++) if((val^b[k])<val) val^=b[k];
			if(val) b[++s]=val;
		}
		ans+=fac[cnt]*(1ll<<(m-s));
		return;
	}
	for(int i=1;i<=cnt+1;i++)
		bl[x]=i,dfs(x+1,max(cnt,i));
}
int main()
{
	read(m);for(int i=1;i<=m;i++)
	{
		scanf("%s",str+1);if(i==1){len=strlen(str+1);while(n*(n-1)/2!=len) n++;}
		for(int j=1,o=0;j<=n;j++)for(int k=j+1;k<=n;k++) mp[i][j][k]=str[++o]-'0';
	}
	fac[1]=1;for(int i=2;i<=n;i++) fac[i]=fac[i-1]*(1-i);
	dfs(1,0),printf("%lld\n",ans);
	return 0;
}
}
int main(){return RKK::main();}
posted @ 2020-07-30 19:27  RikukiIX  阅读(239)  评论(0编辑  收藏  举报