[P5162] WD与积木
每种堆法(理解成名次序列,举例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))-1B(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与积木的更多相关文章
- 洛谷 P5162 WD与积木 解题报告
P5162 WD与积木 题目背景 WD整日沉浸在积木中,无法自拔-- 题目描述 WD想买\(n\)块积木,商场中每块积木的高度都是\(1\),俯视图为正方形(边长不一定相同).由于一些特殊原因,商家会 ...
- 洛谷P5162 WD与积木 [DP,NTT]
传送门 思路 真是非常套路的一道题-- 考虑\(DP\):设\(f_n\)为\(n\)个积木能搭出的方案数,\(g_n\)为所有方案的高度之和. 容易得到转移方程: \[ \begin{align*} ...
- 洛谷 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 ...
- P5162 WD与积木(多项式求逆+生成函数)
传送门 题解 比赛的时候光顾着算某一个\(n\)的答案是多少忘了考虑不同的\(n\)之间的联系了--而且我也很想知道为什么推着推着会变成一个二项式反演-- 设\(f_n\)为\(n\)块积木时的总的层 ...
- Luogu5162 WD与积木(生成函数+多项式求逆)
显然的做法是求出斯特林数,但没有什么优化空间. 考虑一种暴力dp,即设f[i]为i块积木的所有方案层数之和,g[i]为i块积木的方案数.转移时枚举第一层是哪些积木,于是有f[i]=g[i]+ΣC(i, ...
- [Luogu5162]WD与积木(多项式求逆)
不要以为用上Stirling数就一定离正解更近,FFT都是从DP式本身出发的. 设f[i]为i个积木的所有方案的层数总和,g[i]为i个积木的方案数,则答案为$\frac{f[i]}{g[i]}$ 转 ...
- [luogu5162]WD与积木
设$g_{n}$表示$n$个积木放的方案数,枚举最后一层所放的积木,则有$g_{n}=\sum_{i=1}^{n}c(n,i)g_{n-i}$(因为积木有编号的所以要选出$i$个) 将组合数展开并化简 ...
- 【LUOGU???】WD与积木 NTT
题目大意 把 \(n\) 个有标号物品分到一些有标号的箱子中且不允许为空,问期望箱子的数量. 多组询问. \(n\leq 100000\) 题解 记 \(f_i\) 为 \(i\) 个有标号物品分到一 ...
- 【LGP5162】WD与积木
题目 场面过度玄学,容易引起不适 我们发现我们要求的这个期望由分母和分子两部分构成 易发现 \[Ans=\frac{\sum_{i=1}^nS_2(n,i)\times i\times i!}{\su ...
随机推荐
- Finance版本计划
2.0.0.3 1. 支持自定义报表 提供页面自定义报表,根据存储过程,前端页面传参调用 根据存储过程数据集控制简单样式(数字靠右,列宽) 2. 支持报表公式可修改 定义公式规则(文档) 2.0.0. ...
- paxos made more simple
paxos算法是进入分布式领域的一块基石,有关paxos的讨论有很多精彩的详细论述,很多牛人不惜宝贵时间以大幅详尽段落叙述.感谢他们,paxos more simple 理解paxos前,我建议以面到 ...
- Python 3.6安装yaml时报"AttributeError: module 'pip' has no attribute 'main'"和“Non-zero exit code”错误
1.Python 3.6安装yaml时一开始报AttributeError: module 'pip' has no attribute错误,根据网上提供的解决方法修改Pycharm安装目录D:\Pr ...
- CRT-常用命令
1 目录操作 mkdir a ;(新建文件夹) mkdir -p a/b;(新建多及目录文件夹) Rmdir a (a只能是空目录) Rmdir -p a (a可以是多级目录) 2 文件操作 touc ...
- bind()方法
当点击鼠标时,隐藏或显示 p 元素: $("button").bind("click",function(){ $("p").slideTo ...
- django的视图函数
一.视图函数view 视图函数是接收一个请求(request对象),并返回响应的函数 1. HttpResponse响应请求 这个方法是返回字符串一类的,可以识别标签 2. render响应请求 re ...
- DarwinStreamServer 6.0.3 rtsp服务器搭建
14:46:34 环境:Centos 7.3 编译安装 1.下载Darwin源码 http://dss.macosforge.org/downloads/DarwinStreamingSrvr6.0. ...
- 深入理解java虚拟机(二)-----垃圾回收
做一个java程序员很是幸福,不用管不用的对象如何被回收,但是我认为了解一下也不是坏事. 一.如何判断对象已经死亡? 在进行垃圾回收之前,第一件事肯定是判断对象是否已经死亡.1.引用计数算法给对象添加 ...
- Python中使用cx_Oracle调用Oracle存储过程
import cx_Oracle as cx import datetime def execute_sql(): # 声明变量 date_time = datetime.datetime.now() ...
- pip3 install的时候报错timed out
问题: 执行pip install requests报错 Read timed out. 解决方法: 修改超时时间: pip --default-timeout=1000 install -U r ...