二项式反演
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;
}
以上是关于二项式反演的主要内容,如果未能解决你的问题,请参考以下文章