洛谷 P5162 WD与积木 解题报告
P5162 WD与积木
题目背景
WD整日沉浸在积木中,无法自拔……
题目描述
WD想买\(n\)块积木,商场中每块积木的高度都是\(1\),俯视图为正方形(边长不一定相同)。由于一些特殊原因,商家会给每个积木随机一个大小并标号,发给WD。
接下来WD会把相同大小的积木放在一层,并把所有层从大到小堆起来。WD希望知道所有不同的堆法中层数的期望。两种堆法不同当且仅当某个积木在两种堆法中处于不同的层中,由于WD只关心积木的相对大小,因此所有堆法等概率出现,而不是随机的大小等概率(可以看样例理解)。输出结果\(\bmod 998244353\)即可。
(如果还是不能够理解题意,请看样例)
输入输出格式
输入格式:
第一行一个数\(T\),表示询问个数。
接下来\(T\)行每行一个数\(n\),表示WD希望使用\(n\)块积木。
输出格式:
共\(T\)行,每行一个数表示答案\(\bmod 998244353\)。
说明
subtask1(21pts): \(1≤T≤1,000, 1≤n≤1,000\)
subtask2(37pts):\(~1\le T\le 10,~1\le n\le 100,000\)
subtask3(42pts):\(~1\le T\le 100,000,~1\le n\le 100,000\)
当时拿斯特林数推了一会儿没推出来就走了,原来只是部分分啊。
姿势水平屑了,今天稍微给自己普及了一些指数型生成函数。
朴素DP
\(g_n\)代表\(n\)个东西的堆法,就是有标号球和盒子不准空的方案数,就是有序贝尔数,递推的时候枚举第一堆大小。
\]
\(f_i\)代表\(n\)个东西所有堆法的总层数。
\]
从意义上看,\(f_0=0,g_0=1\),不想从意义上看就稍微推一下。
实质还是枚举第一堆的大小,\(g_n\)算的是枚举的这一堆的贡献和,剩下的是其他堆的贡献。
然后构造指数生成函数
\]
然后稍微注意一下发现上面的下标是从\(1\)开始的,于是直接卷会多一个
\]
关于+1-1,今天想到一种理解方式。
\(1\)实际上是一个多项式单位元,像数论卷积定义的\(\epsilon(n)=[n=1]\)那样。
然后+1还是为了\(g_0=1\)考虑的,因为本身这个东西已经封闭了,你得给它打开一个开口啊(天呐我在扯什么
后面-1减的实际上还是\(g_0=1\)
化简一下式子
\]
求逆求出\(G\)就行了
Code:
#include <cstdio>
#include <algorithm>
const int mod=998244353,Gi=332748118;
const int M=(1<<18)+10;
const int N=1e5;
#define mul(a,b) (1ll*(a)*(b)%mod)
#define add(a,b) ((a+b)%mod)
int qp(int d,int k){int f=1;while(k){if(k&1)f=mul(f,d);d=mul(d,d),k>>=1;}return f;}
int fac[M],inv[M],ans[M],H[M],A[M],B[M],D[N],turn[M],len=1;
void NTT(int *a,int typ,int len)
{
int L=-1;for(int i=1;i<len;i<<=1) ++L;
for(int i=1;i<len;i++)
{
turn[i]=turn[i>>1]>>1|(i&1)<<L;
if(i<turn[i]) std::swap(a[i],a[turn[i]]);
}
for(int le=1;le<len;le<<=1)
{
int wn=qp(typ?3:Gi,(mod-1)/(le<<1));
for(int p=0;p<len;p+=le<<1)
{
int w=1;
for(int i=p;i<p+le;i++,w=mul(w,wn))
{
int tx=a[i],ty=mul(w,a[i+le]);
a[i]=add(tx,ty);
a[i+le]=add(tx,mod-ty);
}
}
}
if(!typ)
{
int inv=qp(len,mod-2);
for(int i=0;i<len;i++) a[i]=mul(a[i],inv);
}
}
void polyinv(int *a,int *b,int len)
{
if(len==1){b[0]=qp(a[0],mod-2);return;}
polyinv(a,b,len>>1);
for(int i=0;i<len;i++) A[i]=b[i],B[i]=a[i],A[i+len]=B[i+len]=0;
NTT(A,1,len<<1),NTT(B,1,len<<1);
for(int i=0;i<len<<1;i++) A[i]=mul(A[i],add(2,mod-mul(A[i],B[i])));
NTT(A,0,len<<1);
for(int i=0;i<len;i++) b[i]=A[i];
}
int main()
{
fac[0]=1;for(int i=1;i<=N;i++) fac[i]=mul(fac[i-1],i);
inv[N]=qp(fac[N],mod-2);
for(int i=N-1;~i;i--) inv[i]=mul(inv[i+1],i+1);
for(int i=0;i<=N;i++) H[i]=mod-inv[i];H[0]=1;
while(len<=N) len<<=1;
polyinv(H,ans,len);
for(int i=0;i<len;i++) D[i]=mul(ans[i],fac[i]),H[i]=ans[i];
--ans[0];
NTT(ans,1,len<<1),NTT(H,1,len<<1);
for(int i=0;i<len<<1;i++) ans[i]=mul(ans[i],H[i]);
NTT(ans,0,len<<1);
for(int i=0;i<=N;i++) ans[i]=mul(qp(D[i],mod-2),mul(ans[i],fac[i]));
int T,n;scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
printf("%d\n",ans[n]);
}
return 0;
}
2018.12.31
洛谷 P5162 WD与积木 解题报告的更多相关文章
- 洛谷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 ...
- 洛谷_Cx的故事_解题报告_第四题70
1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h> struct node { long x,y,c; ...
- 洛谷 P2317 [HNOI2005]星际贸易 解题报告
P2317 [HNOI2005]星际贸易 题目描述 输入输出格式 输入格式: 输出格式: 如果可以找到这样的方案,那么输出文件output.txt中包含两个整数X和Y.X表示贸易额,Y表示净利润并且两 ...
- 洛谷 P3802 小魔女帕琪 解题报告
P3802 小魔女帕琪 题目背景 从前有一个聪明的小魔女帕琪,兴趣是狩猎吸血鬼. 帕琪能熟练使用七种属性(金.木.水.火.土.日.月)的魔法,除了能使用这么多种属性魔法外,她还能将两种以上属性组合,从 ...
- 洛谷 P2606 [ZJOI2010]排列计数 解题报告
P2606 [ZJOI2010]排列计数 题目描述 称一个\(1,2,...,N\)的排列\(P_1,P_2...,P_n\)是\(Magic\)的,当且仅当对所以的\(2<=i<=N\) ...
- 洛谷1303 A*B Problem 解题报告
洛谷1303 A*B Problem 本题地址:http://www.luogu.org/problem/show?pid=1303 题目描述 求两数的积. 输入输出格式 输入格式: 两个数 输出格式 ...
- 洛谷 P3084 [USACO13OPEN]照片Photo 解题报告
[USACO13OPEN]照片Photo 题目描述 农夫约翰决定给站在一条线上的\(N(1 \le N \le 200,000)\)头奶牛制作一张全家福照片,\(N\)头奶牛编号\(1\)到\(N\) ...
- 洛谷 P1379 八数码难题 解题报告
P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初 ...
随机推荐
- 2017-2018-4 20155317《网络对抗技术》EXP3 免杀原理与实践
2017-2018-4 20155317<网络对抗技术>EXP3 免杀原理与实践 一.问题回答 (1)杀软是如何检测出恶意代码的?杀软是通过代码特征比对得出的,将检查的代码和自己的特征库的 ...
- SimpleDateFormat-时间格式化中的大小写字符
一.SimpleDateFormat: 这个类是用来格式化date类型数据为指定格式的时间的 使用的而时候,总是区分不清 yyyy-mm-dd yyyy-MM-dd 而使用不同的大小写字符格式化出来的 ...
- 【LG4248】[AHOI2013]差异
[LG4248][AHOI2013]差异 题面 洛谷 题解 后缀数组版做法戳我 我们将原串\(reverse\),根据后缀自动机的性质,两个后缀的\(lcp\)一定是我们在反串后两个前缀的\(lca\ ...
- 页面弹出全屏浮层或遮罩时,禁止底层body滚动
· 解决方法 针对弹出的浮层的 touchmove事件,添加阻止浏览器默认行为. $('.mask-wrapper').on('touchmove', function (event) { // 监听 ...
- stl源码剖析 详细学习笔记 set map
// // set map.cpp // 笔记 // // Created by fam on 15/3/23. // // //---------------------------15/03 ...
- Linux Socket 编程简介
在 TCP/IP 协议中,"IP地址 + TCP或UDP端口号" 可以唯一标识网络通讯中的一个进程,"IP地址+端口号" 就称为 socket.本文以一个简单的 ...
- python3面向对象注意事项
一.面向对象super的作用: class parent(object): def __init__(self): self.test() def test(self): print('parent- ...
- Monkey稳定性测试
1.环境准备:Android SDK环境配置 2.手机连接/模拟器连接 : 1)手机打开开发者模式并允许USB连接 2)校验手机是否连接:打开cmd 输入 adb devices 3.查找apk包名及 ...
- 红黑树的删除详解与思路分析——不同于教科书上的算法(dart语言实现)
对于红黑树的删除,看了数据结构的书,也看了很多网上的讲解和实现,但都不满意.很多讲解都是囫囵吞枣,知其然,不知其所以然,讲的晦涩难懂. 红黑树是平衡二叉树的一种,其删除算法是比较复杂的,因为删除后还要 ...
- 《Linux内核分析》第三周笔记 构造一个简单的Linux系统MenuOS
构造一个简单的Linux系统MenuOS 一.linux内核源代码简介 三大法宝(存储程序计算机.函数调用堆栈.中断)和两把宝剑(中断上下文的切换:保存现场和恢复现场.进程上下文的切换) 1.在lin ...