@exut
2024-10-15T01:29:51.000000Z
字数 4232
阅读 181
组合数学 刷题
我们有一个包含 个非负整数的序列 。
对于所有长度为 且和不超过 的非负整数序列 ,求 之和, 对 取模。
后半部分可以预处理。
考虑题目除了 还有什么约束,其实还有 ,不然这一段乘起来是 没有贡献。
然后发现这样并不能做出来,化不下去了,脑子不够想不出组合意义。
遂挂一篇生成函数的博客在这里,没学完生成函数。
啊于是就可以生成函数搞一下?
考虑 的生成函数 。
现在考虑把 跟 之类的挂上关系,求一个通项公式。
简单推导(把 的上下界省略了):
(关于 ,其实只需要换个元就可以化成 的形式了)
啊于是说我们得到一个式子 。
然后稍微推一下通项,带入求 然后算:
同时有结论 ,带入即证。
答案的计算就可以用一个式子:
然后根据广义二项式定理有一个经典的结论:
于是乎答案就是:
所以答案就是
给定一个长度为 的括号序列,求该括号序列满足如下条件的子序列个数:
1. 长度为正偶数
2. 假设该子序列长度为 ,则该子序列前 个均为 (,后 个均为 )。
对 取模。
。
wok C明显比 B 简单。
看到子序列考虑枚举最后一个 并强制爱选取,从而保证不重不漏。
然后这个 左边有 个 (包括自己) ,右边有 个 ,那么它对答案的贡献就是
上界不需要和 取小,因为多的部分是 没有影响。
然后发现这玩意复杂度有点寄
考虑化一下式子
然后用一下范德蒙德卷鸡
答案就是
恰好是一个很烦的限制,我们可以考虑用二项式反演来搞掉。
设 表示钦定 对点构成祖先后代关系的方案数, 表示恰好。
容易发现
于是问题从一个恰好问题变成了一个至少问题,一下就好多了pwp
看看怎么算
设 表示在 为根的子树内钦定 个祖先后代匹配的方案数。
转移分两步吧,一个树形背包
把各个子树的答案(就是不算 自己) 的答案合并
单独考虑 分颜色讨论
第一种式子是 ,然后这依托看起来 的式子其实是 的,很遗憾我不会证明,就这样吧
第二种就是子树内跟 同颜色的点的个数
,即剩下的自由组合
反演即可
真的难写难调,放个码这题
#include<bits/stdc++.h>using namespace std;#define int long longconst int MAXN=5e3+5,mod=998244353;int frac[MAXN], invfrac[MAXN], inv[MAXN];inline int C(int n, int m) { return frac[n] * invfrac[m] % mod * invfrac[n - m] % mod; }void init(int Max) {frac[0]=invfrac[0]=1;frac[1]=invfrac[1]=inv[1]=1;for(int i=2;i<=Max;i++){frac[i]=frac[i-1]*i%mod;inv[i]=(mod-mod/i)*inv[mod%i]%mod;invfrac[i]=invfrac[i-1]*inv[i]%mod;}}struct edge{int v,nxt;}e[MAXN*2];int hd[MAXN],tot;char s[MAXN];int n,m;void add(int u,int v){e[++tot]={v,hd[u]},hd[u]=tot;}int A[MAXN],B[MAXN];void dfs(int now,int fa){if(s[now]=='0') A[now]++;else B[now]++;for(int i=hd[now];i;i=e[i].nxt){int v=e[i].v;if(v==fa)continue;dfs(v,now);A[now]+=A[v];B[now]+=B[v];}}int siz[MAXN];int dp[MAXN][MAXN];int f[MAXN],g[MAXN];void sol(int now,int fa){siz[now]=0;dp[now][0]=1;for(int i=hd[now];i;i=e[i].nxt){int v=e[i].v;if(v==fa)continue;sol(v,now);for(int j=0;j<=siz[now]+siz[v];j++){g[j]=0;}for(int j=0;j<=siz[now];j++){for(int k=0;k<=siz[v];k++){g[j+k]=(g[j+k]+(dp[now][j]*dp[v][k]%mod))%mod;}}siz[now]+=siz[v];for(int j=0;j<=siz[now];j++)dp[now][j]=g[j];}if(s[now]=='0'){for(int i=siz[now];i>=0;i--){if(B[now]-i>0) dp[now][i+1]=(dp[now][i+1]+dp[now][i]*(B[now]-i)%mod)%mod;}if (dp[now][siz[now]+1]) siz[now]++;}else{for(int i=siz[now];i>=0;i--){if(A[now]-i>0) dp[now][i+1]=(dp[now][i+1]+dp[now][i]*(A[now]-i)%mod)%mod;}if (dp[now][siz[now]+1]) siz[now]++;}}signed main(){cin>>n;init(n);m=n/2;cin>>(s+1);for(int i=1;i<n;i++){int x,y;cin>>x>>y;add(x,y);add(y,x);}dfs(1,0);sol(1,0);for(int i=0;i<=siz[1];i++)g[i]=dp[1][i]*frac[m-i]%mod;for(int i=0;i<=m;i++){for(int j=i,op=1;j<=siz[1];j++,op=-op){f[i]=(f[i]+op*C(j,i)*g[j]%mod+mod)%mod;}cout<<f[i]<<"\n";}}
组合意义天地灭,代数推导保平安!
组合意义天地灭,代数推导保平安!
组合意义天地灭,代数推导保平安!
有 个数对 ,求出
答案对 取模。
先考虑把限制削弱一下:
然后就是大家都喜欢的暴算时间,设
TO BE UPD