游戏【坑】
容斥好题。
由子集反演公式可得:
用f函数代表有至少n个非平局的方案,g代表恰好有n个平局的方案,发现f和g满足前面的方程,于是他们也应当满足后面的关系。于是题目让求g的函数值就转化成了求f的函数值。而f的函数值可以通过树形DP来解决。一棵树内非平局的数量只可能来自于两个地方,一个是某个子树内部的答案,这一部分相当于一个树上背包;另一种是树根和某个点形成的答案,这一部分最后累加即可。要注意的是树上背包的枚举顺序,否则复杂度是假的。f的函数值就是整棵树树根的答案,套上面的公式计算即可。
#include<bits/stdc++.h>
//#define zczc
#define int long long
const int N=5010;
const int mod=998244353;
using namespace std;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
inline int max(int s1,int s2){
return s1<s2?s2:s1;
}
inline int qpow(int s1,int s2){
if(s2==1)return s1;
int an=qpow(s1,s2>>1);
if(s2&1)return an*an%mod*s1%mod;
else return an*an%mod;
}
struct edge{
int t,next;
}e[N<<1];
int head[N],esum;
inline int add(int fr,int to){
e[++esum]=(edge){to,head[fr]};head[fr]=esum;
}
char w[N];
int m,num,a[N],cnt[N],size[N],f[N][N],ff[N];
void dfs(int wh,int fa){
size[wh]=f[wh][0]=1;
for(int i=head[wh],th;i;i=e[i].next){
if((th=e[i].t)==fa)continue;
dfs(th,wh);cnt[wh]+=cnt[th];
for(int j=0;j<=size[wh]+size[th];j++)ff[j]=0;
for(int j=0;j<=size[wh]/2;j++){
for(int k=0;k<=size[th]/2;k++){
if(f[th][k]==0)break;
ff[j+k]=(ff[j+k]+f[wh][j]*f[th][k])%mod;
}
}
size[wh]+=size[th];
for(int j=0;j<=size[wh];j++)f[wh][j]=ff[j];
/*
for(int k=size[wh]/2;k>=0;k--){
for(int j=1;j<=size[th]/2&&j<=k;j++){
if(f[th][j]==0)break;
f[wh][k]+=(f[wh][k-j]*f[th][j])%mod;
}
}
*/
}
if(a[wh])num=size[wh]-cnt[wh];
else num=cnt[wh];
for(int i=size[wh];i;i--){
f[wh][i]+=f[wh][i-1]*max(num-i+1,0);
f[wh][i]%=mod;
}
}
int g[N],u[N],v[N],an[N];
inline int C(int s1,int s2){
return u[s1]*v[s2]%mod*v[s1-s2]%mod;
}
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
#endif
read(m);int s1,s2;
scanf("%s",w+1);
for(int i=1;i<=m;i++)cnt[i]=a[i]=w[i]=='1';//子树内A的个数
for(int i=1;i<m;i++){
read(s1);read(s2);
add(s1,s2);add(s2,s1);
}
dfs(1,0);u[0]=1;
for(int i=1;i<=m/2;i++)u[i]=u[i-1]*i%mod;
for(int i=0;i<=m/2;i++)g[i]=f[1][i]*u[m/2-i]%mod;u[0]=v[0]=1;
for(int i=1;i<=m/2;i++){
u[i]=u[i-1]*i%mod;
v[i]=qpow(u[i],mod-2);
}
for(int i=0;i<=m/2;i++){
for(int j=i;j<=m/2;j++){
an[i]+=((j-i&1)?-1:1)*C(j,i)*g[j]%mod;
an[i]%=mod;
}
printf("%lld\n",(an[i]%mod+mod)%mod);
}
return 0;
}
一如既往,万事胜意
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现