CF1349F 题解
人类操作?可能涉及人类操作。
Easy Version
这个序列发现真的不好刻画。然而我们通过手模或暴力可以得到长度为 \(n\) 的好序列个数为 \(n!\)。于是尝试构造与排列的双射。
事实上我们可以用如下的构造从排列生成一个好的序列:对于排列 \(p\),在数字间填上大于和小于号,序列 \(a_{p_i}\) 的值为 \(p_i\) 前面的小于号个数 \(+1\)。举个例子:对于排列
它的好序列为
同样可以由一个好序列得到唯一的一个排列。由此我们建立了排列和好序列之间的双射。
考虑如何计算排列的贡献。数字 \(k\) 在序列中的出现位置对应到排列上一定是连续的一段,那么枚举每个位置并统计这个位置出现 \(k\) 的排列个数之和就是答案。那么数字 \(k+1\) 的出现次数就是:
组合意义就是前面选出 \(i\) 个数来凑 \(k\) 个小于号,然后后边的随便排。直接爆算是 \(O(n^2)\) 的,可以过 Easy Version。
Hard Version
考虑如何优化上边的东西。
我们有一个欧拉数的通项公式,但是实践证明并不能得到什么更好的形式。换个方向考虑。
考虑二项式反演:设 \(\left|\begin{matrix}n\\k\end{matrix}\right|\) 为钦定 \(k\) 个升高,剩下的放任自流的方案数。立即得到
根据二项式反演,有
那算一下 \(\left|\begin{matrix}n\\k\end{matrix}\right|\)。把用这 \(k\) 个小于号相连的地方分成一段,就有了 \(n-k\) 段,每段都是必须升高的,也就只有一种情况,它的 EGF 即为 \(e^x-1\)。那么有 \(n-k\) 段,全都乘起来,得到
回代:
设 \(s_j=\sum_{i=j}^n[x^i](e^x-1)^{i-j}\),那么如果我们能求出 \(s\) 便可以一次卷积得到答案。
后边不太好算,先看前边。看起来直接求逆就结束了?
有没有这样一种可能,我是说可能,分母的常数项是 \(0\)。
事实上这个有个常见的方法解决这个问题:设 \(G(x)=x^kF(x)\),那么 \(\dfrac 1{G(x)}=x^{-k}\dfrac 1{F(x)}\)。也就是说我们把最低几项砍掉,然后求逆,最后往上偏移几位提取系数即可。
那么考察后边。看起来没法算了。先把系数凑整齐一点:
人类智慧部分:加入一个元分离信息。如下:
那我们只要求出 \([x^n+1]\) 项的所有系数。求一项系数,想到拉格朗日反演。然而复合逆不好构造,因为 \(xF(x)y\) 多了个 \(x\)。
设 \(G(x)=xF(x)\) 和 \(H(x)\) 使得 \(\dfrac{G(x)}{H(G(x))}=x\),则 \(F(x)=H(G(x))\),消掉了 \(x\)。我们先不管 \(H\) 是什么东西。
那么尝试套到 \(\dfrac 1{1-F(x)}\dfrac 1{1-xF(x)y}\) 里边,得到 \(\dfrac 1{1-H(G(x))}\dfrac 1{1-G(x)y}\)。现在有了 \(G(x)\) 的复合形式,考虑构造复合逆 \(P\)。用 \(P\) 代替 \(x\) 代入 \(\dfrac{G(x)}{H(G(x))}=x\),得到 \(P(x)=\dfrac x{H(x)}\)。直接使用扩展拉格朗日反演:(这 b 东西对 \(x\) 求导真 jb 难算,对着题解贺)
直接提取 \(y^m\) 项系数:
结束。哦还没结束,我们还不知道 \(H(x)\) 是什么东西。考虑 \(G(x)=e^x-1\),则有其复合逆为 \(P(x)=\ln(x+1)\),即 \(H(x)=\dfrac x{\ln(x+1)}\)。
结束。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int mod=998244353;
int n,m,wl,a[300010],b[300010],w[300010],jc[300010],inv[300010],f[300010],g[300010],s[300010],Inv[300010];
int h1[300010],h2[300010],h[300010];
#define add(x,y) (x+y>=mod?x+y-mod:x+y)
#define sub(x,y) (x<y?x-y+mod:x-y)
void get(int n){
wl=1;
while(wl<n)wl<<=1;
}
int qpow(int a,int b){
int ans=1;
while(b){
if(b&1)ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return ans;
}
void init(int n){
int t=1;
while((1<<t)<n)t++;
t=min(t-1,21);
w[0]=1;w[1<<t]=qpow(31,1<<21-t);jc[0]=inv[0]=Inv[1]=1;
for(int i=t;i;i--)w[1<<i-1]=1ll*w[1<<i]*w[1<<i]%mod;
for(int i=1;i<(1<<t);i++)w[i]=1ll*w[i&(i-1)]*w[i&-i]%mod;
for(int i=2;i<=n;i++)Inv[i]=1ll*(mod-mod/i)*Inv[mod%i]%mod;
for(int i=1;i<=n;i++)jc[i]=1ll*jc[i-1]*i%mod,inv[i]=1ll*inv[i-1]*Inv[i]%mod;
}
void DIF(int a[],int n){
for(int mid=n>>1;mid>=1;mid>>=1){
for(int i=0,k=0;i<n;i+=mid<<1,k++){
for(int j=0;j<mid;j++){
int x=1ll*a[i+j+mid]*w[k]%mod;
a[i+j+mid]=sub(a[i+j],x);
a[i+j]=add(a[i+j],x);
}
}
}
}
void DIT(int a[],int n){
for(int mid=1;mid<n;mid<<=1){
for(int i=0,k=0;i<n;i+=mid<<1,k++){
for(int j=0;j<mid;j++){
int x=a[i+j+mid];
a[i+j+mid]=1ll*sub(a[i+j],x)*w[k]%mod;
a[i+j]=add(a[i+j],x);
}
}
}
int inv=qpow(n,mod-2);
for(int i=0;i<n;i++)a[i]=1ll*a[i]*inv%mod;
reverse(a+1,a+n);
}
#define mul(f,g,n) for(int i=0;i<n;i++)f[i]=1ll*f[i]*g[i]%mod
void getinv(int n,int f[],int g[]){
get(n);
static int tmp[300010],ret[300010];
for(int i=0;i<wl;i++)g[i]=0;
g[0]=qpow(f[0],mod-2);
for(int len=2;len<=wl;len<<=1){
memcpy(tmp,f,4*len);memcpy(ret,g,2*len);
DIF(tmp,len);DIF(ret,len);mul(tmp,ret,len);
DIT(tmp,len);
memset(tmp,0,2*len);tmp[0]=mod-1;
DIF(tmp,len);mul(ret,tmp,len);
DIT(ret,len);
for(int i=len>>1;i<len;i++)g[i]=mod-ret[i];
}
for(int i=n;i<wl;i++)g[i]=0;
for(int i=0;i<wl;i++)tmp[i]=ret[i]=0;
}
void dao(int f[],int n){
for(int i=1;i<n;i++)f[i-1]=1ll*f[i]*i%mod;
f[n-1]=0;
}
void jifen(int f[],int n){
for(int i=n;i>=1;i--)f[i]=1ll*f[i-1]*Inv[i]%mod;
f[0]=0;
}
void getln(int n,int f[],int g[]){
getinv(n,f,g);get(n<<1);
for(int i=n;i<wl;i++)f[i]=g[i]=0;
dao(f,wl);
DIF(f,wl);DIF(g,wl);mul(g,f,wl);
DIT(g,wl);
jifen(g,wl);
for(int i=n;i<wl;i++)g[i]=0;
}
int buf[300010<<4];
int *f1[20][8],*g1[20][8];
void bruteexp(int f[],int g[],int l,int r){
if(!l)f[l]=1;
else f[l]=1ll*f[l]*Inv[l]%mod;
for(int i=l+1;i<=r;i++){
for(int j=l;j<i;j++){
int x=1ll*f[j]*g[i-j]%mod;
f[i]=add(f[i],x);
}
f[i]=1ll*f[i]*Inv[i]%mod;
}
}
void cdq(int l,int r,int dep,int f[],int g[],void brute(int f[],int g[],int l,int r)){
if(r-l+1<=32){
brute(f,g,l,r);return;
}
static int tmp[300010];
int d=1<<((dep-1)*3);
for(int i=0;;i++){
int L=l+i*d,R=min(r,L+d-1);
if(i){
for(int j=0;j<(d<<1);j++)tmp[j]=0;
for(int j=0;j<i;j++){
for(int k=0;k<(d<<1);k++){
int x=1ll*f1[dep][j][k]*g1[dep][i-j][k]%mod;
tmp[k]=add(tmp[k],x);
}
}
DIT(tmp,d<<1);
for(int i=L;i<=R;i++)f[i]=add(f[i],tmp[i-L+d]);
}
cdq(L,R,dep-1,f,g,brute);
if(R==r)return;
for(int j=0;j<(d<<1);j++)f1[dep][i][j]=0;
for(int j=L;j<=R;j++)f1[dep][i][j-L]=f[j];
DIF(f1[dep][i],d<<1);
}
}
void solve(int f[],int g[],int n,void brute(int f[],int g[],int l,int r)){
for(int i=0;i<n;i++)f[i]=0;
if(n<=128){
brute(f,g,0,n-1);return;
}
int len=1,dep=0;
while(len<n)len<<=3,dep++;len>>=3;
int *now=buf;
for(int i=1;i<=dep;i++){
int d=1<<((i-1)*3),mn=min((n-1)/d,7);
for(int j=1;j<=mn;j++){
int l=(j-1)*d+1,r=min(n-1,(j+1)*d-1);
f1[i][j-1]=now;now+=d<<1;
g1[i][j]=now;now+=d<<1;
for(int k=0;k<(1<<d);k++)g1[i][j][k]=0;
for(int k=l;k<=r;k++)g1[i][j][k-l+1]=g[k];
DIF(g1[i][j],d<<1);
}
}
cdq(0,n-1,dep,f,g,brute);
}
void getexp(int n,int f[],int g[]){
for(int i=0;i<n;i++)f[i]=1ll*f[i]*i%mod;
solve(g,f,n,bruteexp);
}
void getpow(int n,int f[],int g[],int k){
getln(n,f,g);
for(int i=0;i<n;i++)f[i]=1ll*g[i]*k%mod;
getexp(n,f,g);
}
void Mul(int a[],int b[],int n,int m,int c[]){
static int A[300010],B[300010];
get(n+m);
for(int i=0;i<n;i++)A[i]=a[i];
for(int i=0;i<m;i++)B[i]=b[i];
DIF(A,wl);DIF(B,wl);mul(A,B,wl);DIT(A,wl);
for(int i=0;i<n+m-1;i++)c[i]=A[i];
for(int i=0;i<wl;i++)A[i]=B[i]=0;
}
int main(){
scanf("%d",&n);
m=n+2;init(m+1<<1);
for(int i=0;i<=m;i++)a[i]=mod-inv[i+2];
getinv(m+1,a,g);
for(int i=0;i<m;i++)s[i]=g[i+1];
for(int i=0;i<wl;i++)a[i]=0;
for(int i=0;i<=m;i++)a[i]=(i&1)?mod-Inv[i+1]:Inv[i+1];
getinv(m+1,a,h);
for(int i=0;i<=m;i++)f[i]=h[i];
getpow(m+1,f,h1,n+1);
for(int i=0;i<=m;i++)g[i]=h[i];
dao(g,m+1);
for(int i=0;i<=m;i++)h2[i]=h1[i];
Mul(h2,g,m,m,h2);for(int i=m;i<wl;i++)h2[i]=0;
for(int i=0;i<wl;i++)g[i]=0;
for(int i=0;i<m;i++)g[i]=mod-h[i+1];
getinv(m+1,g,f);
for(int i=0;i<m;i++)g[i]=f[i],f[i]=0;
get(m<<1);
DIF(g,wl);DIF(h1,wl);DIF(h2,wl);
mul(h1,g,wl);DIT(h1,wl);for(int i=m;i<wl;i++)h1[i]=0;
mul(h2,g,wl);DIT(h2,wl);for(int i=m;i<wl;i++)h2[i]=0;
DIF(h2,wl);
mul(h2,g,wl);DIT(h2,wl);for(int i=m;i<wl;i++)h2[i]=0;
s[0]=n;
for(int i=1;i<m;i++){
int m=n-i+1;
s[i]=(s[i]-1ll*(1ll*h1[n-m+2]*m%mod+h2[n-m+2])%mod*Inv[n+1]%mod+mod)%mod;
}
for(int i=0;i<n;i++)s[i]=1ll*s[i]*jc[i]%mod;
for(int i=n;i<wl;i++)f[i]=s[i]=0;
for(int i=0;i<n;i++)f[i]=(i&1)?mod-inv[i]:inv[i];
reverse(s,s+n);
DIF(f,wl);DIF(s,wl);mul(f,s,wl);DIT(f,wl);reverse(f,f+n);
for(int i=0;i<n;i++){
f[i]=1ll*f[i]*jc[n]%mod*inv[i]%mod;printf("%d ",f[i]);
}
puts("");
return 0;
}