Luogu5162 WD与积木(生成函数+多项式求逆)
显然的做法是求出斯特林数,但没有什么优化空间。
考虑一种暴力dp,即设f[i]为i块积木的所有方案层数之和,g[i]为i块积木的方案数。转移时枚举第一层是哪些积木,于是有f[i]=g[i]+ΣC(i,j)·f[i-j],g[i]=ΣC(i,j)·g[i-j] (j=1~i)。
考虑优化 。我们发现这个转移非常像卷积。写成卷积形式,有f[i]=g[i]+Σi!·Σf[i-j]/j!/(i-j)!,g[i]=i!·Σg[i-j]/j!/(i-j)!。直接分治NTT即可。
诶是不是强行多了个log?考虑构造出生成函数。g比较简单,将该式写成g[i]/i!=Σg[i-j]/j!/(i-j)!,设g[i]/i!生成函数为G(x),inv(i!)生成函数为H(x),则有G(x)=G(x)·H(x)-G(x)+1,也即G(x)=1/(2-H(x))。f同样写成f[i]/i!=g[i]/i!+Σf[i-j]/j!/(i-j)!,则有F(x)=G(x)+F(x)·H(x)-F(x)-1,也即F(x)=G(x)·(G(x)-1)。多项式求逆即可。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define P 998244353
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<''||c>'')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int T,n,t,r[<<],f[<<],g[<<],h[<<],tmp[<<];
int ksm(int a,int k)
{
int s=;
for (;k;k>>=,a=1ll*a*a%P) if (k&) s=1ll*s*a%P;
return s;
}
int inv(int a){return ksm(a,P-);}
void DFT(int *a,int n,int g)
{
for (int i=;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]);
for (int i=;i<=n;i<<=)
{
int wn=ksm(g,(P-)/i);
for (int j=;j<n;j+=i)
{
int w=;
for (int k=j;k<j+(i>>);k++,w=1ll*w*wn%P)
{
int x=a[k],y=1ll*w*a[k+(i>>)]%P;
a[k]=(x+y)%P,a[k+(i>>)]=(x-y+P)%P;
}
}
}
}
void mul(int *a,int *b,int n,int op)
{
for (int i=;i<n;i++) r[i]=(r[i>>]>>)|(i&)*(n>>);
DFT(a,n,),DFT(b,n,);
if (op==) for (int i=;i<n;i++) a[i]=1ll*a[i]*b[i]%P;
else for (int i=;i<n;i++) a[i]=1ll*a[i]*(P+-1ll*a[i]*b[i]%P)%P;
DFT(a,n,inv());
int t=inv(n);
for (int i=;i<n;i++) a[i]=1ll*a[i]*t%P;
}
void getinv(int n)
{
g[]=;
for (int i=;i<=n;i<<=)
{
for (int j=i;j<(i<<);j++) tmp[j]=;
for (int j=;j<i;j++) tmp[j]=h[j];
mul(g,tmp,i<<,);
for (int j=i;j<(i<<);j++) g[j]=;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
T=read();int t=;while (t<=(N<<)) t<<=;
h[]=h[]=;for (int i=;i<=N;i++) h[i]=P-1ll*(P/i)*h[P%i]%P;
for (int i=;i<=N;i++) h[i]=1ll*h[i]*h[i-]%P;
for (int i=;i<=N;i++) h[i]=(P-h[i])%P;
h[]=(h[]+)%P;
getinv(t);
for (int i=N+;i<t;i++) g[i]=;
memcpy(f,g,sizeof(f));f[]--;if (f[]<) f[]+=P;
mul(f,g,t,);DFT(g,t,inv());int u=inv(t);for (int i=;i<t;i++) g[i]=1ll*g[i]*u%P;
while (T--)
{
n=read();
printf("%d\n",1ll*f[n]*inv(g[n])%P);
}
return ;
}
Luogu5162 WD与积木(生成函数+多项式求逆)的更多相关文章
- 洛谷 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\)块积木时的总的层 ...
- 【XSY2612】Comb Avoiding Trees 生成函数 多项式求逆 矩阵快速幂
题目大意 本题的满二叉树定义为:不存在只有一个儿子的节点的二叉树. 定义一棵满二叉树\(A\)包含满二叉树\(B\)当且经当\(A\)可以通过下列三种操作变成\(B\): 把一个节点的两个儿子同时删掉 ...
- 2019.01.01 bzoj3625:小朋友和二叉树(生成函数+多项式求逆+多项式开方)
传送门 codeforces传送门codeforces传送门codeforces传送门 生成函数好题. 卡场差评至今未过 题意简述:nnn个点的二叉树,每个点的权值KaTeX parse error: ...
- 【BZOJ3625】【codeforces438E】小朋友和二叉树 生成函数+多项式求逆+多项式开根
首先,我们构造一个函数$G(x)$,若存在$k∈C$,则$[x^k]G(x)=1$. 不妨设$F(x)$为最终答案的生成函数,则$[x^n]F(x)$即为权值为$n$的神犇二叉树个数. 不难推导出,$ ...
- COGS 2259 异化多肽 —— 生成函数+多项式求逆
题目:http://cogs.pro:8080/cogs/problem/problem.php?pid=2259 如果构造生成函数是许多个 \( (1+x^{k}+x^{2k}+...) \) 相乘 ...
- 洛谷P4721 【模板】分治 FFT(生成函数+多项式求逆)
传送门 我是用多项式求逆做的因为分治FFT看不懂…… upd:分治FFT的看这里 话说这个万恶的生成函数到底是什么东西…… 我们令$F(x)=\sum_{i=0}^\infty f_ix^i,G(x) ...
- 牛客IOI周赛17-提高组 卷积 生成函数 多项式求逆 数列通项公式
LINK:卷积 思考的时候 非常的片面 导致这道题没有推出来. 虽然想到了设生成函数 G(x)表示最后的答案的普通型生成函数 不过忘了化简 GG. 容易推出 \(G(x)=\frac{F(x)}{1- ...
- 洛谷P4841 城市规划(生成函数 多项式求逆)
题意 链接 Sol Orz yyb 一开始想的是直接设\(f_i\)表示\(i\)个点的无向联通图个数,枚举最后一个联通块转移,发现有一种情况转移不到... 正解是先设\(g(n)\)表示\(n\)个 ...
随机推荐
- java.lang.NoClassDefFoundError: org.androidpn.client.PersistentConnectionListener
在运行AndroidpnClient项目时出现了java.lang.NoClassDefFoundError: org.androidpn.client.PersistentConnectionLis ...
- jquery的$(document).ready()与js的window.onload区别
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> ...
- 学会如何使用Github进行托管代码和用markdown撰写心得
这次作业是学会如何使用Github进行托管代码和用markdown撰写心得. 1.掌握使用Git进行代码版本,使用github进行代码托管.(git使用,推荐imooc公开课: 公开课 ) 登录 gi ...
- php中经常使用的string函数
strpos() ---返回字符串在另一字符串中首次出现的位置 strrpos() ---查找字符串在另一字符串中最后出现的位置 strchr() === strstr() ---找到字符 ...
- AbelSu区块链应用场景收集
1.基于智能合约的众筹 众筹项目的资金通常由一个中心化不可变更且开放的数据库来控制,这个数据库可以追踪所有出资人. 虽然如此,我们可以用一种去中心化的方式来实现,而且只要创建一个代币就可以追踪资金.一 ...
- 2017-2018-2 『网络对抗技术』Exp3:免杀原理与实践
1. 免杀原理与实践说明 一.实验说明 任务一:正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion,自己利用shellcode编程等免杀工具或技巧:(1.5分) ...
- win7笔记本VirtualBox安装黑苹果MacOS 10.13
环境 时间:2018.04.09,没有指明时间的教程都是耍流氓 笔记本:某州优雅A460P-i7G D2,4G内存,Intel Core i7-2670QM四核八线程(老笔记本勉强能用),ssd硬盘, ...
- 内存和CPU资源控制
数据库系统的资源是指内存和CPU(处理器)资源,拥有资源的多寡,决定了数据查询的性能.当一个SQL Server实例上,拥有多个独立的工作负载(workload)时,使用资源管理器(Resource ...
- css怎样去掉多个Img标签之间的间隙
在写css的时候经常会遇到这样的情况,两张宽度加起来是2n的图片,在宽度为2n的容器中放不下,这是因为两张图片之间有一段间隙的缘故,产生这种现象的原因是浏览器把两个img标签之间的空格当成了空白节点. ...
- telnet协议:简介与安装使用
Telnet简介 Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式.它为用户提供了在本地计算机上完成远程主机工作的能力.在终端使用者的电脑上使用teln ...