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

将组合数展开并化简,得到$\frac{g_{n}}{n!}=\sum_{i=1}^{n}\frac{g_{n-i}}{i!(n-i)!}$,明显是一个分治fft的形式,转换为多项式求逆:

令$g_{n}$的指数生成函数为$G(x)=\sum_{i=0}^{\infty}\frac{g_{i}}{i!}x^{i}$,再令$H(x)=\sum_{i=0}^{\infty}\frac{x^{i}}{i!}$,考虑$H(x)G(x)$,代入并将$i=0$和$j=0$提出可得$H(x)G(x)=\sum_{i=0}^{\infty}(\sum_{j=0}^{i}H(x)[j]\cdot G(x)[i-j])x^{i}=2G(x)-1$,即$G(x)=\frac{1}{2-H(x)}$

设$f_{n}$表示$n$个积木放的方案数的层数之和,那么根据期望的定义,答案$E=\frac{f_{n}}{g_{n}}$

类似的,可以写出$f_{n}$的递推式,即$f_{n}=g_{n}+\sum_{i=1}^{n}c(n,i)f_{n-i}$($g_{n}$是因为每一个方案都要+1),将$g_{n}$的表达式展开,有$\frac{f_{n}}{n!}=\sum_{i=1}^{n}\frac{f_{n-i}+g_{n-i}}{i!(n-i)!}$,同样去转换为多项式求逆:

令$f_{n}$的指数生成函数为$F(x)=\sum_{i=0}^{\infty}\frac{f_{i}}{i!}x^{i}$,$H(x)$和$G(x)$相同,考虑$H(x)(G(x)+F(x))$,类似上面可得$H(x)(G(x)+F(x))=G(x)+2F(x)$(注意$f_{0}=0$),即$F(x)=\frac{(H(x)-1)G(x)}{2-H(x)}=(H(x)-1)G(x)^{2}$

最终答案即$\frac{F(x)[n]}{G(x)[n]}$(都除以了$n!$),注意最后一步不能将$\frac{F(x)}{G(x)}$作为结果,因为这不等于答案

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 #define N (1<<18)
  4. 4 #define mod 998244353
  5. 5 int t,n,a[N],c[N],h[N],g[N],f[N];
  6. 6 int ksm(int n,int m){
  7. 7 if (!m)return 1;
  8. 8 int s=ksm(n,m>>1);
  9. 9 s=1LL*s*s%mod;
  10. 10 if (m&1)s=1LL*s*n%mod;
  11. 11 return s;
  12. 12 }
  13. 13 void ntt(int *a,int n,int p){
  14. 14 for(int i=0;i<(1<<n);i++){
  15. 15 int rev=0;
  16. 16 for(int j=0;j<n;j++)rev=rev*2+((i&(1<<j))>0);
  17. 17 if (i<rev)swap(a[i],a[rev]);
  18. 18 }
  19. 19 for(int i=2;i<=(1<<n);i*=2){
  20. 20 int s=ksm(3,(mod-1)/i);
  21. 21 if (p)s=ksm(s,mod-2);
  22. 22 for(int j=0;j<(1<<n);j+=i)
  23. 23 for(int k=0,ss=1;k<(i>>1);k++,ss=1LL*ss*s%mod){
  24. 24 int x=a[j+k],y=1LL*a[j+k+(i>>1)]*ss%mod;
  25. 25 a[j+k]=(x+y)%mod;
  26. 26 a[j+k+(i>>1)]=(x+mod-y)%mod;
  27. 27 }
  28. 28 }
  29. 29 if (p){
  30. 30 int s=ksm((1<<n),mod-2);
  31. 31 for(int i=0;i<(1<<n);i++)a[i]=1LL*a[i]*s%mod;
  32. 32 }
  33. 33 }
  34. 34 void Inv(int *a,int *b,int n){
  35. 35 if (!n){
  36. 36 b[0]=ksm(a[0],mod-2);
  37. 37 return;
  38. 38 }
  39. 39 Inv(a,b,n-1);
  40. 40 for(int i=0;i<(1<<n);i++)c[i]=a[i];
  41. 41 for(int i=(1<<n);i<(1<<n+1);i++)c[i]=0;
  42. 42 ntt(c,n+1,0);
  43. 43 ntt(b,n+1,0);
  44. 44 for(int i=0;i<(1<<n+1);i++)b[i]=1LL*b[i]*(mod+2-1LL*c[i]*b[i]%mod)%mod;
  45. 45 ntt(b,n+1,1);
  46. 46 for(int i=(1<<n);i<(1<<n+1);i++)b[i]=0;
  47. 47 }
  48. 48 int main(){
  49. 49 a[0]=1;
  50. 50 for(int i=1;i<N;i++)a[i]=1LL*a[i-1]*ksm(i,mod-2)%mod;
  51. 51 h[0]=(mod+2-a[0])%mod;
  52. 52 for(int i=1;i<N/2;i++)h[i]=(mod-a[i])%mod;
  53. 53 Inv(h,g,17);
  54. 54 memcpy(f,g,sizeof(g));
  55. 55 ntt(f,18,0);
  56. 56 for(int i=0;i<N;i++)f[i]=1LL*f[i]*f[i]%mod;
  57. 57 ntt(f,18,1);
  58. 58 for(int i=N/2;i<N;i++)f[i]=0;
  59. 59 ntt(f,18,0);
  60. 60 h[0]=0;
  61. 61 for(int i=1;i<N/2;i++)h[i]=a[i];
  62. 62 ntt(h,18,0);
  63. 63 for(int i=0;i<N;i++)f[i]=1LL*f[i]*h[i]%mod;
  64. 64 ntt(f,18,1);
  65. 65 scanf("%d",&t);
  66. 66 while (t--){
  67. 67 scanf("%d",&n);
  68. 68 printf("%lld\n",1LL*f[n]*ksm(g[n],mod-2)%mod);
  69. 69 }
  70. 70 }

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

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

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

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

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

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

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

  4. [P5162] WD与积木

    每种堆法(理解成名次序列,举例3,3,8,2和7,7,100,2都对应2,2,1,3这个名次序列)等概率出现:题目中"两种堆法不同当且仅当某个积木在两种堆法中处于不同的层中"可见这 ...

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

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

  6. 洛谷 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 ...

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

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

  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. 微软 SqlHelper代码、功能、用法介绍:高效的组件

    数据访问组件SqlHelper数据访问组件是一组通用的访问数据库的代码,在所有项目中都可以用,一般不需要修改.本节使用的是Microsoft提供的数据访问助手,其封装很严密,且应用简单. 首先要先添加 ...

  2. 三分钟极速体验:Java版人脸检测

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  3. Linux上传下载神器之 lrzsz

    在开发的过程中,经常遇到 需要在 Linux 和 Windows 之间上传下载文件的情况 这时,一般都是使用 FTP 或者 WinSCP 工具进行上传下载, 虽然也能解决问题,但是这些工具需要在本地安 ...

  4. Java:ThreadLocal小记

    Java:ThreadLocal小记 说明:这是看了 bilibili 上 黑马程序员 的课程 java基础教程由浅入深全面解析threadlocal 后做的笔记 内容 ThreadLocal 介绍 ...

  5. Scrum Meeting 0531

    零.说明 日期:2021-5-31 任务:简要汇报两日内已完成任务,计划后两日完成任务 一.进度情况 组员 负责 两日内已完成的任务 后两日计划完成的任务 困难 qsy PM&前端 完成后端管 ...

  6. [对对子队]会议记录5.15(Scrum Meeting2)

    今天已完成的工作 吴昭邦 ​ 工作内容:衔接循环指令系统,搭建第4关 ​ 相关issue:实现循环组件 ​ 相关签入:feat: 将模型加入第四关 第四关可以顺利通过 何瑞 ​ 工作内容:衔接循环指令 ...

  7. IPv6(诞生原因、数据报格式、与IPv4的不同、地址表现形式、基本地址类型、IPv6与IPv4的过渡策略)

    文章转自:https://blog.csdn.net/weixin_43914604/article/details/105297642 学习课程:<2019王道考研计算机网络> 学习目的 ...

  8. Spring Security:如何在Postman中优雅地测试后端API(前后端分离)

    前言 在Postman中可以编写和执行自动化测试,使用 JavaScript 编写基本的 API 测试,自由编写任何用于自动化测试的测试方案. 在POSTMAN中读取Cookie值 1. 我们需要向& ...

  9. TCP/IP简述

    一.TCP/IP简述 TCP/IP从字面异议看起来是指TCP和IP两种协议,实际上,它只是利用IP进行通信时必须用到的协议群的统称.具体的来说,IP或ICMP.TCP或UDP.Telnet或FTP.以 ...

  10. Vulnhub实战-dr4g0n b4ll靶机👻

    Vulnhub实战-dr4g0n b4ll靶机 地址:http://www.vulnhub.com/entry/dr4g0n-b4ll-1,646/ 描述:这篇其实没有什么新奇的技巧,用到的提权方式就 ...