[关闭]
@exut 2024-10-15T01:29:51.000000Z 字数 4232 阅读 181

10.3 组合数学专题训练

组合数学 刷题


A [ARC110D] Binomial Coefficient is Fun

题目描述

我们有一个包含 个非负整数的序列

对于所有长度为 且和不超过 的非负整数序列 ,求 之和, 对 取模。

sol

后半部分可以预处理。

考虑题目除了 还有什么约束,其实还有 ,不然这一段乘起来是 没有贡献。

然后发现这样并不能做出来,化不下去了,脑子不够想不出组合意义。

遂挂一篇生成函数的博客在这里,没学完生成函数

啊于是就可以生成函数搞一下?

考虑 的生成函数

现在考虑把 之类的挂上关系,求一个通项公式。

简单推导(把 的上下界省略了):

(关于 ,其实只需要换个元就可以化成 的形式了)

啊于是说我们得到一个式子

然后稍微推一下通项,带入求 然后算:

同时有结论 ,带入即证。

答案的计算就可以用一个式子:

然后根据广义二项式定理有一个经典的结论:

于是乎答案就是:


由组合恒等式:

所以答案就是

算就行了,相信少爷机)


C Anton and School - 2

Anton and School - 2

给定一个长度为 的括号序列,求该括号序列满足如下条件的子序列个数:
1. 长度为正偶数
2. 假设该子序列长度为 ,则该子序列前 个均为 (,后 个均为 )

取模。

sol

wok C明显比 B 简单。

看到子序列考虑枚举最后一个 并强制选取,从而保证不重不漏。

然后这个 左边有 (包括自己) ,右边有 ,那么它对答案的贡献就是

上界不需要和 取小,因为多的部分是 没有影响。

然后发现这玩意复杂度有点寄

考虑化一下式子

然后用一下范德蒙德卷鸡

答案就是

对于每个 算一遍就行


E 游戏

sol

恰好是一个很烦的限制,我们可以考虑用二项式反演来搞掉。

表示钦定 对点构成祖先后代关系的方案数, 表示恰好。

容易发现

然后反演一下可得

于是问题从一个恰好问题变成了一个至少问题,一下就好多了pwp

看看怎么算

表示在 为根的子树内钦定 个祖先后代匹配的方案数。

转移分两步吧,一个树形背包

第一种式子是 ,然后这依托看起来 的式子其实是 的,很遗憾我不会证明,就这样吧

第二种就是子树内跟 同颜色的点的个数

,即剩下的自由组合

反演即可

真的难写难调,放个码这题

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define int long long
  4. const int MAXN=5e3+5,mod=998244353;
  5. int frac[MAXN], invfrac[MAXN], inv[MAXN];
  6. inline int C(int n, int m) { return frac[n] * invfrac[m] % mod * invfrac[n - m] % mod; }
  7. void init(int Max) {
  8. frac[0]=invfrac[0]=1;
  9. frac[1]=invfrac[1]=inv[1]=1;
  10. for(int i=2;i<=Max;i++){
  11. frac[i]=frac[i-1]*i%mod;
  12. inv[i]=(mod-mod/i)*inv[mod%i]%mod;
  13. invfrac[i]=invfrac[i-1]*inv[i]%mod;
  14. }
  15. }
  16. struct edge{
  17. int v,nxt;
  18. }e[MAXN*2];
  19. int hd[MAXN],tot;
  20. char s[MAXN];
  21. int n,m;
  22. void add(int u,int v){
  23. e[++tot]={v,hd[u]},hd[u]=tot;
  24. }
  25. int A[MAXN],B[MAXN];
  26. void dfs(int now,int fa){
  27. if(s[now]=='0') A[now]++;
  28. else B[now]++;
  29. for(int i=hd[now];i;i=e[i].nxt){
  30. int v=e[i].v;
  31. if(v==fa)continue;
  32. dfs(v,now);
  33. A[now]+=A[v];
  34. B[now]+=B[v];
  35. }
  36. }
  37. int siz[MAXN];
  38. int dp[MAXN][MAXN];
  39. int f[MAXN],g[MAXN];
  40. void sol(int now,int fa){
  41. siz[now]=0;
  42. dp[now][0]=1;
  43. for(int i=hd[now];i;i=e[i].nxt){
  44. int v=e[i].v;
  45. if(v==fa)continue;
  46. sol(v,now);
  47. for(int j=0;j<=siz[now]+siz[v];j++){
  48. g[j]=0;
  49. }
  50. for(int j=0;j<=siz[now];j++){
  51. for(int k=0;k<=siz[v];k++){
  52. g[j+k]=(g[j+k]+(dp[now][j]*dp[v][k]%mod))%mod;
  53. }
  54. }
  55. siz[now]+=siz[v];
  56. for(int j=0;j<=siz[now];j++)
  57. dp[now][j]=g[j];
  58. }
  59. if(s[now]=='0'){
  60. for(int i=siz[now];i>=0;i--){
  61. if(B[now]-i>0) dp[now][i+1]=(dp[now][i+1]+dp[now][i]*(B[now]-i)%mod)%mod;
  62. }
  63. if (dp[now][siz[now]+1]) siz[now]++;
  64. }
  65. else{
  66. for(int i=siz[now];i>=0;i--){
  67. if(A[now]-i>0) dp[now][i+1]=(dp[now][i+1]+dp[now][i]*(A[now]-i)%mod)%mod;
  68. }
  69. if (dp[now][siz[now]+1]) siz[now]++;
  70. }
  71. }
  72. signed main(){
  73. cin>>n;
  74. init(n);
  75. m=n/2;
  76. cin>>(s+1);
  77. for(int i=1;i<n;i++){
  78. int x,y;
  79. cin>>x>>y;
  80. add(x,y);add(y,x);
  81. }
  82. dfs(1,0);
  83. sol(1,0);
  84. for(int i=0;i<=siz[1];i++)
  85. g[i]=dp[1][i]*frac[m-i]%mod;
  86. for(int i=0;i<=m;i++){
  87. for(int j=i,op=1;j<=siz[1];j++,op=-op){
  88. f[i]=(f[i]+op*C(j,i)*g[j]%mod+mod)%mod;
  89. }
  90. cout<<f[i]<<"\n";
  91. }
  92. }

G BBQ Hard

组合意义天地灭,代数推导保平安!

组合意义天地灭,代数推导保平安!

组合意义天地灭,代数推导保平安!

[AGC001E] BBQ Hard

题面翻译

个数对 ,求出

答案对 取模。

sol

先考虑把限制削弱一下:

最后除以 就行了

然后就是大家都喜欢的暴算时间,设


没写完先发出来吧

TO BE UPD

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注