二项式反演

Posted segmenttree

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二项式反演相关的知识,希望对你有一定的参考价值。

我好像只会背公式,用容斥来理解稍微好一点

程序的精妙的地方还是在其他部分,这个只不过是一个容斥

题目

游戏

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=5100;
const int mod=998244353;
struct edge
{
	int to,nxt;
}e[N*2];
int h[N],E=0;
int n,m,cal[N],used[N],siz[N];
ll dp[N][N],t[N];
char a[N];
ll fac[N],inv[N],g[N],f[N];
ll neg[N];
ll qpow(ll a,ll b)
{
	ll res=1;
	for(;b>0;b/=2,a=a*a%mod) if(b%2) res=1ll*res*a%mod;
	return res;
}
void add(ll &x,ll y)
{
	x+=y;
	if(x>=mod) x-=mod;
	return;
}
void addedge(int u,int v)
{
	E++;
	e[E].to=v,e[E].nxt=h[u];
	h[u]=E;
	return;
}
ll C(int n,int m)
{
	if(n<m) return 0;
	return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
void dfs1(int u,int fa)
{
	cal[u]=used[u];
	siz[u]=1;
	for(int i=h[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs1(v,u);
		cal[u]+=cal[v];
		siz[u]+=siz[v];
	}
	return;
}
void dfs(int u,int fa)
{
	siz[u]=1;
	dp[u][0]=1;
	for(int i=0;i<=n;i++) t[i]=0;
	for(int i=h[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs(v,u);
		for(int j=0;j<=siz[u]+siz[v];j++) t[j]=0; 
		for(int j=siz[u];j>=0;j--)
		{
			for(int k=1;k<=siz[v];k++)
			{
				add(t[j+k],dp[u][j]*dp[v][k]%mod);
			}
			add(t[j],dp[u][j]*dp[v][0]%mod);
		}
		siz[u]+=siz[v];
		for(int j=0;j<=siz[u];j++) dp[u][j]=t[j]; 
	}

	int cho;
	if(used[u]) cho=siz[u]-cal[u];
	else cho=cal[u];
	for(int i=cho;i>=0;i--) add(dp[u][i+1],dp[u][i]*(cho-i)%mod);
	dp[u][0]=1;	
	return;
}
int main()
{
	scanf("%d",&n);
	neg[0]=1;
	for(int i=1;i<=n;i++) neg[i]=neg[i-1]*(mod-1)%mod;
	m=n/2;
	fac[0]=1;
	for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
	for(int i=0;i<=n;i++) inv[i]=qpow(fac[i],mod-2);
	scanf("%s",a+1);
	for(int i=1;i<=n;i++) used[i]=a[i]==‘1‘;
	int u,v;
	for(int i=1;i<=n-1;i++)
	{
		scanf("%d%d",&u,&v);
		addedge(u,v);
		addedge(v,u);
	}
	dfs1(1,0);
	dfs(1,0);
	for(int i=0;i<=m;i++) g[i]=dp[1][i]*fac[m-i]%mod;
	for(int i=0;i<=m;i++) 
	{
		for(int j=i;j<=m;j++)
		{
			add(f[i],1ll*neg[j-i]*C(j,i)%mod*g[j]%mod);
		}
		printf("%lld
",f[i]);
	}
	printf("
");
	return 0;
}

以上是关于二项式反演的主要内容,如果未能解决你的问题,请参考以下文章

反演魔术---二项式反演

Re:从零开始的二项式反演

二项式反演及其应用

二项式反演公式证明

二项式反演(非详细)

二项式反演学习笔记