P6478 [NOI Online #2 提高组]游戏(树dp+广义容斥)
P6478 [NOI Online #2 提高组]游戏
“恰好”的方案数不好求,我们对这个问题进行转化:设
那么我们可以在
设
求出
#include<bits/stdc++.h>
#define ll long long
using namespace std;
namespace FGF
{
int n,m;
const int N=5005;
const int mo=998244353;
char s[N];
struct edg{
int to,nxt;
}e[N<<1];
int cnt,head[N],siz[N],sz[2][N],a[N];
ll dp[N][N],tmp[N],fac[N],g[N],f[N],C[N][N];
void add(int u,int v)
{
cnt++;
e[cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
void dfs(int u,int fa)
{
siz[u]=1,sz[a[u]][u]=1,dp[u][0]=1;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa)continue;
dfs(v,u);
for(int j=0;j<=min(siz[u]+siz[v],m);j++)tmp[j]=0;
for(int j=0;j<=min(siz[u],m);j++)
for(int k=0;k<=min(siz[v],m-j);k++)
tmp[j+k]=(tmp[j+k]+dp[u][j]*dp[v][k]%mo)%mo;
siz[u]+=siz[v];
sz[0][u]+=sz[0][v],sz[1][u]+=sz[1][v];
for(int j=0;j<=min(siz[u],m);j++)dp[u][j]=tmp[j];
}
for(int i=sz[a[u]^1][u];i>=0;i--)
dp[u][i+1]=(dp[u][i+1]+dp[u][i]*(sz[a[u]^1][u]-i)%mo)%mo;
}
void init()
{
for(int i=0;i<=n;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mo;
}
fac[0]=1;
for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mo;
}
void work()
{
scanf("%d",&n);m=n>>1;
scanf("%s",s+1);
for(int i=1;i<=n;i++)a[i]=s[i]-'0';
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs(1,0);
init();
for(int i=0;i<=m;i++)g[i]=dp[1][i]*fac[m-i]%mo;
for(int i=0;i<=m;i++)
for(int j=i;j<=m;j++)
if((j-i)&1)f[i]=(f[i]-C[j][i]*g[j]%mo+mo)%mo;
else f[i]=(f[i]+C[j][i]*g[j]%mo)%mo;
for(int i=0;i<=m;i++)
printf("%lld\n",f[i]);
}
}
int main()
{
FGF::work();
return 0;
}