码迷,mamicode.com
首页 > 其他好文 > 详细

二项式反演

时间:2020-06-05 19:20:42      阅读:68      评论:0      收藏:0      [点我收藏+]

标签:程序   typedef   理解   include   i++   部分   https   一个   namespace   

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

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

题目

游戏

#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\n",f[i]);
	}
	printf("\n");
	return 0;
}

二项式反演

标签:程序   typedef   理解   include   i++   部分   https   一个   namespace   

原文地址:https://www.cnblogs.com/SegmentTree/p/13051383.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!