每种堆法(理解成名次序列,举例3,3,8,2和7,7,100,2都对应2,2,1,3这个名次序列)等概率出现;题目中“两种堆法不同当且仅当某个积木在两种堆法中处于不同的层中”可见这是个组合问题,于是设一个名次的生成函数F(x)=sum i=1->inf 1*x^i/(i!) 。因为F(x)的常数项为0,有F^inf(x)=0。

名次序列的方案数的生成函数:A(x) = sum i=0->inf F^i(x) = 1/(1-F(x))

名次序列的各种方案的名次个数之和的生成函数:B(x) = sum i=0->inf i*F^i(x) = F(x)/(1-F(x))^2 = A^2(x)-A(x) = A(x)*(A(x)-1)

预处理出A(x),B(x)的前MAX_N项系数,对于n,答案为B(x)[n]/A(x)[n]。

注意事项

关于从0开始求和

如果是从1开始的情形:

A(x)=sum i=1->inf F^i(x)

= F(x)*(1-F^inf(x))/(1-F(x))

= F(x)/(1-F(x))

= (1-(1-F(x)))/(1-F(x))

= 1/(1-F(x))-1

B(x)=sum i=1-> inf i*F^i(x)

= ...

= F(x)/(1-F(x))^2-1

抛开A(x)[0]和B(x)[0],似乎关系并没有什么影响。

关于EGF的卷积运算

某个生成函数F(x)=sum i=0->inf a[i]*x^i/(i!)

对于EGF意义下的卷积

F(x)*F(x)=sum i=0->inf (sum j=0->i C(i,j)*a[j]*a[i-j]) x^i/(i!)

= sum i=0->inf (sum j=0->i (i!)/(j!)/((i-j)!)*a[j]*a[i-j]) x^i/(i!)

= sum i=0->inf (sum j=0->i a[j]/(j!)*a[i-j]/((i-j)!)) x^i

与在OGF意义下的卷积

F(x)=sum i=0->inf b[i]*x^i ,b[i]=a[i]/(i!)

F(x)*F(x)=sum i=0->inf (sum j=0->i b[j]*b[i-j]) x^i

完全一致.

这告诉我们在使用EGF的具体计算时,可以将1/(i!)放到系数中去用一般多项式算法计算得到一个OGF结构,

所得到的函数的各系数再乘上i!就是正确的EGF结构下的标志序列了;显然,该性质也适用于EGF的连续卷积!

换句话说,EGF的标志序列尽管除以一个i!,然后与OGF无异地各种操作,最终结果再让标志序列乘上i!就好了。

代码实现中因为除法关系没有乘上i!。

参考实现

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAX_N=1e5+10;
  4. const int P=998244353,G=3;
  5. int a[MAX_N<<2];
  6. int b[MAX_N<<2];
  7. int c[MAX_N<<2];
  8. int f[MAX_N<<2];
  9. int r[MAX_N<<2];
  10. int frr[MAX_N];
  11. int qpow(long long x,int y) {
  12. long long c=1;
  13. for(; y; y>>=1, x=x*x%P)
  14. if(y&1) c=c*x%P;
  15. return c;
  16. }
  17. void ntt(int *a,int lmt,int tp) {
  18. for(int i=0; i<lmt; ++i) if(i<r[i]) swap(a[i],a[r[i]]);
  19. for(int m=1; m<lmt; m<<=1) {
  20. int wm=qpow(G,(P-1)/(m<<1));
  21. if(tp==-1) wm=qpow(wm,P-2);
  22. for(int i=0; i<lmt; i+=(m<<1)) {
  23. long long w=1, tmp;
  24. for(int j=0; j<m; ++j, w=w*wm%P) {
  25. tmp=w*a[i+j+m]%P;
  26. a[i+j+m]=(a[i+j]-tmp+P)%P;
  27. a[i+j]=(a[i+j]+tmp)%P;
  28. }
  29. }
  30. }
  31. if(tp==-1) {
  32. long long tmp=qpow(lmt,P-2);
  33. for(int i=0; i<lmt; ++i) a[i]=tmp*a[i]%P;
  34. }
  35. }
  36. void polyrev(int deg,int *a,int *b) {
  37. if(deg==1) {
  38. b[0]=qpow(a[0],P-2);
  39. return;
  40. }
  41. polyrev((deg+1)>>1,a,b);
  42. int lmt=1, l=0;
  43. while(lmt<(deg<<1)) lmt<<=1, ++l;
  44. for(int i=0; i<lmt; ++i) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
  45. for(int i=0; i<deg; ++i) c[i]=a[i];
  46. fill(c+deg,c+lmt,0);
  47. ntt(c,lmt,1), ntt(b,lmt,1);
  48. for(int i=0; i<lmt; ++i) b[i]=(2LL-1LL*c[i]*b[i]%P+P)%P*b[i]%P;
  49. ntt(b,lmt,-1);
  50. fill(b+deg,b+lmt,0);
  51. }
  52. int main() {
  53. long long fac=1;
  54. for(int i=1; i<MAX_N; ++i) fac=fac*i%P;
  55. frr[MAX_N-1]=qpow(fac,P-2);
  56. for(int i=MAX_N-1; i; --i) frr[i-1]=1LL*i*frr[i]%P;
  57. for(int i=0; i<MAX_N; ++i) a[i]=P-frr[i];
  58. a[0]=(a[0]+2)%P;
  59. polyrev(MAX_N,a,b);
  60. for(int i=0; i<MAX_N; ++i) a[i]=f[i]=b[i];
  61. int lmt=1;
  62. while(lmt<=MAX_N) lmt<<=1; lmt<<=1;
  63. a[0]=(a[0]+P-1)%P;
  64. ntt(f,lmt,1), ntt(a,lmt,1);
  65. for(int i=0; i<lmt; ++i) f[i]=1LL*f[i]*a[i]%P;
  66. ntt(f,lmt,-1);
  67. int T,n;
  68. scanf("%d",&T);
  69. while(T--) {
  70. scanf("%d",&n);
  71. printf("%lld\n",1LL*f[n]*qpow(b[n],P-2)%P);
  72. }
  73. return 0;
  74. }

感谢@Weng_Weiji的答疑,思路也是来自于他(她?)的题解;代码参考了@Owen_codeisking

也感谢来自其它大佬的恶意嘲讽

[P5162] WD与积木的更多相关文章

  1. 洛谷 P5162 WD与积木 解题报告

    P5162 WD与积木 题目背景 WD整日沉浸在积木中,无法自拔-- 题目描述 WD想买\(n\)块积木,商场中每块积木的高度都是\(1\),俯视图为正方形(边长不一定相同).由于一些特殊原因,商家会 ...

  2. 洛谷P5162 WD与积木 [DP,NTT]

    传送门 思路 真是非常套路的一道题-- 考虑\(DP\):设\(f_n\)为\(n\)个积木能搭出的方案数,\(g_n\)为所有方案的高度之和. 容易得到转移方程: \[ \begin{align*} ...

  3. 洛谷 P5162 WD与积木【多项式求逆】

    设f[i]为i个积木能堆出来的种类,g[i]为i个积木能堆出来的种类和 \[ f[n]=\sum_{i=1}^{n}C_{n}^{i}g[n-i] \] \[ g[n]=\sum_{i=1}^{n}C ...

  4. P5162 WD与积木(多项式求逆+生成函数)

    传送门 题解 比赛的时候光顾着算某一个\(n\)的答案是多少忘了考虑不同的\(n\)之间的联系了--而且我也很想知道为什么推着推着会变成一个二项式反演-- 设\(f_n\)为\(n\)块积木时的总的层 ...

  5. Luogu5162 WD与积木(生成函数+多项式求逆)

    显然的做法是求出斯特林数,但没有什么优化空间. 考虑一种暴力dp,即设f[i]为i块积木的所有方案层数之和,g[i]为i块积木的方案数.转移时枚举第一层是哪些积木,于是有f[i]=g[i]+ΣC(i, ...

  6. [Luogu5162]WD与积木(多项式求逆)

    不要以为用上Stirling数就一定离正解更近,FFT都是从DP式本身出发的. 设f[i]为i个积木的所有方案的层数总和,g[i]为i个积木的方案数,则答案为$\frac{f[i]}{g[i]}$ 转 ...

  7. [luogu5162]WD与积木

    设$g_{n}$表示$n$个积木放的方案数,枚举最后一层所放的积木,则有$g_{n}=\sum_{i=1}^{n}c(n,i)g_{n-i}$(因为积木有编号的所以要选出$i$个) 将组合数展开并化简 ...

  8. 【LUOGU???】WD与积木 NTT

    题目大意 把 \(n\) 个有标号物品分到一些有标号的箱子中且不允许为空,问期望箱子的数量. 多组询问. \(n\leq 100000\) 题解 记 \(f_i\) 为 \(i\) 个有标号物品分到一 ...

  9. 【LGP5162】WD与积木

    题目 场面过度玄学,容易引起不适 我们发现我们要求的这个期望由分母和分子两部分构成 易发现 \[Ans=\frac{\sum_{i=1}^nS_2(n,i)\times i\times i!}{\su ...

随机推荐

  1. BCode解码练习

    在学习BT协议中的一个小练习 参考了 https://github.com/airtrack/bitwave 具体B编码解释 可以自行搜索或者参考 这篇文章 bittorrent 学习(一) 种子文件 ...

  2. Django高级实战 开发企业级问答网站完整

    资源获取链接点击这里 Django高级实战 开发企业级问答网站 从实际需求分析开始,实现当今主流知识问答应用的功能,包括动态.文章.问答.私信.消息通知.搜索.个人中心,打造企业级知识问答网站,由此全 ...

  3. 最小化webpack项目

    先把代码贴出来,以后慢慢加说明 参考资料:入门 Webpack,看这篇就够了 / webpack 搭建自动打开,刷新浏览器 一.功能代码1.index.html <!DOCTYPE html&g ...

  4. mvc @helper 创建用户自定义html

    转载地址:https://www.cnblogs.com/caofangsheng/p/5670071.html

  5. 从零开始学java (四)反射

    反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. ...

  6. 解决vs验证控件报错” WebForms UnobtrusiveValidationMode 需要“jquery”ScriptResourceMapping。请添加一个名为 jquery (区分大小写)的 ScriptResourceMapping”问题

    将RequiredFieldValidator的 EnableClientScript属性设置成 False 适用于大多验证控件

  7. freeType移植总结①——使用keil编译freeType2库

    在各个技术博客搜索相关资料后,终于将freeType的源码用keil工程编译通过,这里记录一下步骤和遇到的问题. 因为网上的资料都是旧版本freeType的工程,这里博主使用的是freeType2.9 ...

  8. Git系列:第七篇-Maven项目下提交时忽略不必要的文件或文件夹

    用.gitignore文件来进行忽略不必要的文件或文件夹 在开发中我们要提交的内容大都是src里的全部文件(java文件).gitignore(忽略文件)pom.xml(maven配置文件)----- ...

  9. 浅谈Spring中的IOC容器

    一.IOC.DI基本概念 IoC(Inversion of Control)控制反转指的是把对象的创建,初始化,销毁等工作交给容器来做.由容器控制对象的生命周期(传统方式中是由我们程序员主动创建对象. ...

  10. 小程序 mpvue自定义底部导航栏

    1.在compontents新建文件放入 <template> <section class="tabBar-wrap"> <article clas ...