每种堆法(理解成名次序列,举例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!。

参考实现

#include <bits/stdc++.h>
using namespace std; const int MAX_N=1e5+10;
const int P=998244353,G=3; int a[MAX_N<<2];
int b[MAX_N<<2];
int c[MAX_N<<2];
int f[MAX_N<<2];
int r[MAX_N<<2];
int frr[MAX_N]; int qpow(long long x,int y) {
long long c=1;
for(; y; y>>=1, x=x*x%P)
if(y&1) c=c*x%P;
return c;
}
void ntt(int *a,int lmt,int tp) {
for(int i=0; i<lmt; ++i) if(i<r[i]) swap(a[i],a[r[i]]);
for(int m=1; m<lmt; m<<=1) {
int wm=qpow(G,(P-1)/(m<<1));
if(tp==-1) wm=qpow(wm,P-2);
for(int i=0; i<lmt; i+=(m<<1)) {
long long w=1, tmp;
for(int j=0; j<m; ++j, w=w*wm%P) {
tmp=w*a[i+j+m]%P;
a[i+j+m]=(a[i+j]-tmp+P)%P;
a[i+j]=(a[i+j]+tmp)%P;
}
}
}
if(tp==-1) {
long long tmp=qpow(lmt,P-2);
for(int i=0; i<lmt; ++i) a[i]=tmp*a[i]%P;
}
}
void polyrev(int deg,int *a,int *b) {
if(deg==1) {
b[0]=qpow(a[0],P-2);
return;
}
polyrev((deg+1)>>1,a,b);
int lmt=1, l=0;
while(lmt<(deg<<1)) lmt<<=1, ++l;
for(int i=0; i<lmt; ++i) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0; i<deg; ++i) c[i]=a[i];
fill(c+deg,c+lmt,0);
ntt(c,lmt,1), ntt(b,lmt,1);
for(int i=0; i<lmt; ++i) b[i]=(2LL-1LL*c[i]*b[i]%P+P)%P*b[i]%P;
ntt(b,lmt,-1);
fill(b+deg,b+lmt,0);
} int main() {
long long fac=1;
for(int i=1; i<MAX_N; ++i) fac=fac*i%P;
frr[MAX_N-1]=qpow(fac,P-2);
for(int i=MAX_N-1; i; --i) frr[i-1]=1LL*i*frr[i]%P;
for(int i=0; i<MAX_N; ++i) a[i]=P-frr[i];
a[0]=(a[0]+2)%P;
polyrev(MAX_N,a,b);
for(int i=0; i<MAX_N; ++i) a[i]=f[i]=b[i];
int lmt=1;
while(lmt<=MAX_N) lmt<<=1; lmt<<=1;
a[0]=(a[0]+P-1)%P;
ntt(f,lmt,1), ntt(a,lmt,1);
for(int i=0; i<lmt; ++i) f[i]=1LL*f[i]*a[i]%P;
ntt(f,lmt,-1); int T,n;
scanf("%d",&T);
while(T--) {
scanf("%d",&n);
printf("%lld\n",1LL*f[n]*qpow(b[n],P-2)%P);
}
return 0;
}

感谢@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. springcolud文章收藏

    https://blog.csdn.net/dyc87112/column/info/14412https://blog.csdn.net/dyc87112/article/details/79357 ...

  2. pl/sql调试存储过程

    1.找到对应的存储过程 2.在存储过程名称上右键,选择Test 3.点击1标识的按钮(begin debugger),选择2开始调试 4.存储过程如需参数,需要在右侧下方的表格区域(3)填入对应的值即 ...

  3. 【NIFI】 Apache NiFI 集群搭建

    NiFI 集群介绍 NiFi集群架构 NiFi采用Zero-Master Clustering范例.集群中的每个节点对数据执行相同的任务,但每个节点都在不同的数据集上运行.其中一个节点自动选择(通过A ...

  4. KVM 虚拟机的热迁移

    热迁移:顾名思义在虚拟机不关机的情况下将KVM虚拟机进行迁移 准备工作:两台KVM虚拟机,一台nfs虚拟机,centos7.4系统 主机 IP地址 主机名 KVM01 10.00.11 kvm01 K ...

  5. 《Linux就该这么学》第十九天课程

    今天对“Linux就该这么学”课程做个收尾 最后一张使用LNMP架构部署动态网站环境 第1步:下载及解压源码包文件.为了方便在网络中传输,源码包文件通常会在归档后使用gzip或bzip2等格式进行压缩 ...

  6. CentOS 7.6下解决登录MySQL时,ERROR 1045 (28000): Access denied for user root@localhost (using password: YES

    https://blog.csdn.net/sinat_35406909/article/details/79763782

  7. python模块:logging

    # Copyright 2001-2016 by Vinay Sajip. All Rights Reserved. # # Permission to use, copy, modify, and ...

  8. HDU 6346 整数规划 (最佳完美匹配)

    整数规划 Time Limit: 5500/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Subm ...

  9. [Java算法] -- 1. 常用排序之冒泡排序和选择排序

    使用Java语言实现冒泡排序和选择排序 推荐一个数据结构可视化的网站:http://zh.visualgo.net/zh (暂时访问不了) 对排序不太熟悉的朋友,建议去上面的网站学习一下,你将会发现一 ...

  10. 转发对python装饰器的理解

    [Python] 对 Python 装饰器的理解的一些心得分享出来给大家参考   原文  http://blog.csdn.net/sxw3718401/article/details/3951958 ...