【LUOGU???】WD与积木 NTT
题目大意
把 \(n\) 个有标号物品分到一些有标号的箱子中且不允许为空,问期望箱子的数量。
多组询问。
\(n\leq 100000\)
题解
记 \(f_i\) 为 \(i\) 个有标号物品分到一些有标号的箱子中且不允许为空的箱子的数量之和。
记 \(g_i\) 为 \(i\) 个有标号物品分到一些有标号的箱子中且不允许为空的方案数。
答案为 \(\frac{f_n}{g_n}\)。
转移就是枚举最后一个箱子放了多少物品:
g_i&=\sum_{j=1}^ig_{i-j}\binom{i}{j}\\
f_i&=\sum_{j=1}^i(f_{i-j}+g_{i-j})\binom{i}{j}\\
\end{align}
\]
记 \(F(x)=\sum_{i\geq 0}f_i\frac{x^i}{i!},G(x)=\sum_{i\geq 0}g_i\frac{x^i}{i!}\),(即这两个数列的EGF)有:
G(x)&=-G(x)+e^xG(x)+1\\
2G(x)-e^xG(x)&=1\\
G(x)&=\frac{1}{2-e^x}\\
F(x)&=-F(x)-G(x)+e^x(F(x)+G(x))+1\\
(2-e^x)F(x)+(1-e^x)G(x)&=1\\
F(x)&=\frac{(e^x-1)G(x)}{2-e^x}\\
&=\frac{e^x-1}{(2-e^x)^2}
\end{align}
\]
直接卷积+求逆即可。
时间复杂度:\(O(n\log n)\)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<functional>
#include<cmath>
#include<vector>
#include<assert.h>
//using namespace std;
using std::min;
using std::max;
using std::swap;
using std::sort;
using std::reverse;
using std::random_shuffle;
using std::lower_bound;
using std::upper_bound;
using std::unique;
using std::vector;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef std::pair<int,int> pii;
typedef std::pair<ll,ll> pll;
void open(const char *s){
#ifndef ONLINE_JUDGE
char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
void open2(const char *s){
#ifdef DEBUG
char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;}
void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
const ll p=998244353;
const int N=270000;
ll fp(ll a,ll b)
{
ll s=1;
for(;b;b>>=1,a=a*a%p)
if(b&1)
s=s*a%p;
return s;
}
namespace ntt
{
const int W=262144;
int rev[N];
int *w[20];
void init()
{
ll s=fp(3,(p-1)/W);
w[18]=new int[1<<17];
w[18][0]=1;
for(int i=1;i<W/2;i++)
w[18][i]=w[18][i-1]*s%p;
for(int i=17;i>=1;i--)
{
w[i]=new int[1<<(i-1)];
for(int j=0;j<1<<(i-1);j++)
w[i][j]=w[i+1][j<<1];
}
}
void ntt(ll *a,int n,int t)
{
for(int i=1;i<n;i++)
{
rev[i]=(rev[i>>1]>>1)|(i&1?n>>1:0);
if(rev[i]>i)
swap(a[i],a[rev[i]]);
}
for(int i=2,l=1;i<=n;i<<=1,l++)
for(int j=0;j<n;j+=i)
for(int k=0;k<i/2;k++)
{
ll u=a[j+k];
ll v=a[j+k+i/2]*w[l][k];
a[j+k]=(u+v)%p;
a[j+k+i/2]=(u-v)%p;
}
if(t==-1)
{
reverse(a+1,a+n);
ll inv=fp(n,p-2);
for(int i=0;i<n;i++)
a[i]=a[i]*inv%p;
}
}
void add(ll *a,ll *b,ll *c,int n,int m,int l)
{
static ll a1[N];
int k=max(n,m);
for(int i=0;i<=k;i++)
a1[i]=0;
for(int i=0;i<=n;i++)
a1[i]=(a1[i]+a[i])%p;
for(int i=0;i<=m;i++)
a1[i]=(a1[i]+b[i])%p;
for(int i=0;i<=l;i++)
c[i]=a1[i];
}
void mul(ll *a,ll *b,ll *c,int n,int m,int l)
{
static ll a1[N],a2[N];
int k=1;
while(k<=n+m)
k<<=1;
for(int i=0;i<k;i++)
a1[i]=a2[i]=0;
for(int i=0;i<=n;i++)
a1[i]=a[i];
for(int i=0;i<=m;i++)
a2[i]=b[i];
ntt(a1,k,1);
ntt(a2,k,1);
for(int i=0;i<k;i++)
a1[i]=a1[i]*a2[i]%p;
ntt(a1,k,-1);
for(int i=0;i<=l;i++)
c[i]=(a1[i]+p)%p;
}
void getinv(ll *a,ll *b,int n)
{
if(n==1)
{
b[0]=fp(a[0],p-2);
return;
}
getinv(a,b,n>>1);
static ll a1[N],a2[N];
for(int i=0;i<n<<1;i++)
a1[i]=a2[i]=0;
for(int i=0;i<n;i++)
a1[i]=a[i];
for(int i=0;i<n>>1;i++)
a2[i]=b[i];
ntt(a1,n<<1,1);
ntt(a2,n<<1,1);
for(int i=0;i<n<<1;i++)
a1[i]=a2[i]*(2-a1[i]*a2[i]%p)%p;
ntt(a1,n<<1,-1);
for(int i=0;i<n;i++)
b[i]=(a1[i]+p)%p;
}
}
int n=100000;
int k=131072;
ll inv[N],fac[N],ifac[N];
ll a[N],b[N],f[N],g[N],ans[N],c[N];
int main()
{
open("d");
ntt::init();
inv[1]=fac[0]=fac[1]=ifac[0]=ifac[1]=1;
for(int i=2;i<=n;i++)
{
inv[i]=(-p/i*inv[p%i]%p+p)%p;
fac[i]=fac[i-1]*i%p;
ifac[i]=ifac[i-1]*inv[i]%p;
}
for(int i=1;i<=n;i++)
{
a[i]=ifac[i];
b[i]=-ifac[i];
// a[i]=1;
// b[i]=-1;
}
a[0]=0;
b[0]=1;
ntt::getinv(b,g,k);
ntt::mul(g,g,c,n,n,n);
ntt::mul(a,c,f,n,n,n);
for(int i=1;i<=n;i++)
{
f[i]=(f[i]*fac[i]%p+p)%p;
g[i]=(g[i]*fac[i]%p+p)%p;
}
for(int i=1;i<=n;i++)
ans[i]=(f[i]*fp(g[i],p-2)%p+p)%p;
int t;
scanf("%d",&t);
int x;
while(t--)
{
scanf("%d",&x);
printf("%lld\n",ans[x]);
}
return 0;
}
【LUOGU???】WD与积木 NTT的更多相关文章
- 洛谷 P5162 WD与积木 解题报告
P5162 WD与积木 题目背景 WD整日沉浸在积木中,无法自拔-- 题目描述 WD想买\(n\)块积木,商场中每块积木的高度都是\(1\),俯视图为正方形(边长不一定相同).由于一些特殊原因,商家会 ...
- 洛谷P5162 WD与积木 [DP,NTT]
传送门 思路 真是非常套路的一道题-- 考虑\(DP\):设\(f_n\)为\(n\)个积木能搭出的方案数,\(g_n\)为所有方案的高度之和. 容易得到转移方程: \[ \begin{align*} ...
- [P5162] WD与积木
每种堆法(理解成名次序列,举例3,3,8,2和7,7,100,2都对应2,2,1,3这个名次序列)等概率出现:题目中"两种堆法不同当且仅当某个积木在两种堆法中处于不同的层中"可见这 ...
- Luogu5162 WD与积木(生成函数+多项式求逆)
显然的做法是求出斯特林数,但没有什么优化空间. 考虑一种暴力dp,即设f[i]为i块积木的所有方案层数之和,g[i]为i块积木的方案数.转移时枚举第一层是哪些积木,于是有f[i]=g[i]+ΣC(i, ...
- P5162 WD与积木(多项式求逆+生成函数)
传送门 题解 比赛的时候光顾着算某一个\(n\)的答案是多少忘了考虑不同的\(n\)之间的联系了--而且我也很想知道为什么推着推着会变成一个二项式反演-- 设\(f_n\)为\(n\)块积木时的总的层 ...
- [luogu5162]WD与积木
设$g_{n}$表示$n$个积木放的方案数,枚举最后一层所放的积木,则有$g_{n}=\sum_{i=1}^{n}c(n,i)g_{n-i}$(因为积木有编号的所以要选出$i$个) 将组合数展开并化简 ...
- [Luogu 4245] 任意模数NTT
Description 给定 \(2\) 个多项式 \(F(x), G(x)\),请求出 \(F(x) * G(x)\). 系数对 \(p\) 取模,且不保证 \(p\) 可以分解成 \(p = a ...
- [Luogu5162]WD与积木(多项式求逆)
不要以为用上Stirling数就一定离正解更近,FFT都是从DP式本身出发的. 设f[i]为i个积木的所有方案的层数总和,g[i]为i个积木的方案数,则答案为$\frac{f[i]}{g[i]}$ 转 ...
- 【LGP5162】WD与积木
题目 场面过度玄学,容易引起不适 我们发现我们要求的这个期望由分母和分子两部分构成 易发现 \[Ans=\frac{\sum_{i=1}^nS_2(n,i)\times i\times i!}{\su ...
随机推荐
- Redis原理及使用
一:原理介绍 1:什么是redis? Redis 是一个基于内存的高性能key-value数据库. 2:Reids的特点Redis本质上是一个Key-Value类型的内存数据库,很像memcache ...
- Jquer + Ajax 制作上传图片文件
没什么 说的 直接 上代码 //选择图片并上传 function selectImg(node){ var f = node.value; var file = node.files[0]; if( ...
- while,for,if输入账号密码判断(还请各位大牛能够优化,本人刚学习一周)
AccountNumber1 = [] password1 = [] flag = True while flag: num = 0 a = 1 print('-----------这是个欢迎界面-- ...
- Manacher's Algorithm(马拉车算法)
## 背景 该算法用于求字符串的最长回文子串长度. ## 参考文章 >[最长回文子串——Manacher 算法](https://segmentfault.com/a/1190000003914 ...
- linux的一些命令,面试经常碰到的
1 查询所有java进程ps -A | grep java解释一下这个命令的意思,ps 是查看系统当前进程的命令,参数 -A(注意,是大写,linux中是区分大小写的)是显示所有程序,| 这个是管道符 ...
- Yii2设计模式——注册树模式
应用举例 在Yii.php中: <?php class ServiceLocator extends Component { //保存实例化的对象,每个对象都是单例,且有唯一string类型的I ...
- SpringAOP(5)
2019-03-08/14:22:58 演示:登陆核心业务类与日志周边功能实现AOP面向切面思想 jar包:https://share.weiyun.com/5GOFouP 学习资料:http://h ...
- Odoo 菜单美化的扩展模块
详见: http://www.oejia.net/blog/2018/07/07/oejia_menu_about.html Odoo 菜单美化主题,odoo默认的菜单算是简洁好用的,如果您觉得还少了 ...
- 章节十、5-CSS---用CSS 通配符定位元素
以下演示操作以该网址中的输入框为例:https://learn.letskodeit.com/p/practice 一.css样式中有三种通配符“^.$.*” 语法:tag[attribute< ...
- mssql server for docker on MacOs
1. install 1.下载镜像 docker pull microsoft/mssql-server-linux 使用该命令就可以把数据库的docker镜像下载下来. 2.创建并运行容器 dock ...