CF1349F 题解

人类操作?可能涉及人类操作。

Easy Version

这个序列发现真的不好刻画。然而我们通过手模或暴力可以得到长度为 \(n\) 的好序列个数为 \(n!\)。于是尝试构造与排列的双射。

事实上我们可以用如下的构造从排列生成一个好的序列:对于排列 \(p\),在数字间填上大于和小于号,序列 \(a_{p_i}\) 的值为 \(p_i\) 前面的小于号个数 \(+1\)。举个例子:对于排列

\[3,5,1,4,6,2 \]

它的好序列为

\[2,4,1,3,2,4 \]

同样可以由一个好序列得到唯一的一个排列。由此我们建立了排列和好序列之间的双射。

考虑如何计算排列的贡献。数字 \(k\) 在序列中的出现位置对应到排列上一定是连续的一段,那么枚举每个位置并统计这个位置出现 \(k\) 的排列个数之和就是答案。那么数字 \(k+1\) 的出现次数就是:

\[ans_k=\sum_{i=\max(1,k)}^n\left\langle\begin{matrix}i\\k\end{matrix}\right\rangle\binom ni(n-i)! \]

组合意义就是前面选出 \(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|=\sum_{i=k}\left\langle\begin{matrix}n\\i\end{matrix}\right\rangle\binom ik \]

根据二项式反演,有

\[\left\langle\begin{matrix}n\\k\end{matrix}\right\rangle=\sum_{i=k}(-1)^{i-k}\binom ik\left|\begin{matrix}n\\i\end{matrix}\right| \]

那算一下 \(\left|\begin{matrix}n\\k\end{matrix}\right|\)。把用这 \(k\) 个小于号相连的地方分成一段,就有了 \(n-k\) 段,每段都是必须升高的,也就只有一种情况,它的 EGF 即为 \(e^x-1\)。那么有 \(n-k\) 段,全都乘起来,得到

\[\left|\begin{matrix}n\\k\end{matrix}\right|=n![x^n](e^x-1)^{n-k} \]

回代:

\[\begin{aligned} ans_k=&\sum_{i=k}^n\binom ni(n-i)!\sum_{j=k}^n(-1)^{j-k}\binom jki![x^i](e^x-1)^{i-j}\\ =&n!\sum_{i=k}^n\sum_{j=k}^n(-1)^{j-k}\binom jk[x^i](e^x-1)^{i-j}\\ =&\frac{n!}{k!}\sum_{j=k}^n\frac{(-1)^{j-k}}{(j-k)!}j!\sum_{i=j}^n[x^i](e^x-1)^{i-j} \end{aligned} \]

\(s_j=\sum_{i=j}^n[x^i](e^x-1)^{i-j}\),那么如果我们能求出 \(s\) 便可以一次卷积得到答案。

\[\begin{aligned} s_k=&\sum_{i=k}^n[x^i](e^x-1)^{i-k}\\ =&\sum_{i=0}^{n-k}[x^{i+k}](e^x-1)^i\\ =&\sum_{i=0}^{n-k}[x^k](\frac{e^x-1}x)^i\\ =&[x^k]\left(\frac{1-F(x)^{n-k+1}}{1-F(x)}\right)\qquad\left(F(x)=\frac{e^x-1}x\right)\\ =&[x^k]\frac 1{1-F(x)}-[x^k]\frac{F(x)^{n-k+1}}{1-F(x)} \end{aligned} \]

后边不太好算,先看前边。看起来直接求逆就结束了?

有没有这样一种可能,我是说可能,分母的常数项是 \(0\)

事实上这个有个常见的方法解决这个问题:设 \(G(x)=x^kF(x)\),那么 \(\dfrac 1{G(x)}=x^{-k}\dfrac 1{F(x)}\)。也就是说我们把最低几项砍掉,然后求逆,最后往上偏移几位提取系数即可。

那么考察后边。看起来没法算了。先把系数凑整齐一点:

\[[x^k]\frac{F(x)^{n-k+1}}{1-F(x)}=[x^{n+1}]\frac{(xF(x))^{n-k+1}}{1-F(x)} \]

人类智慧部分:加入一个元分离信息。如下:

\[\begin{aligned} &[x^{n+1}]\frac{(xF(x))^{n-k+1}}{1-F(x)}\\ =&[x^{n+1}y^{n-k+1}]\sum_{i=1}\frac{(xF(x)y)^i}{1-F(x)}\\ =&[x^{n+1}y^{n-k+1}]\frac 1{1-F(x)}\frac 1{1-xF(x)y} \end{aligned} \]

那我们只要求出 \([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 难算,对着题解贺)

\[\begin{aligned} &[x^{n+1}]\dfrac 1{1-H(G(x))}\dfrac 1{1-G(x)y}\\ =&\frac 1{n+1}[x^n]\frac{y+H'(x)-yH(x)-xyH'(x)}{(1-H(x))^2(1-xy)^2}\left(\frac x{P(x)}\right)^{n+1}\\ =&\frac 1{n+1}[x^n]\frac{y(1-H(x))+(1-xy)H'(x)}{(1-H(x))^2(1-xy)^2}H(x)^{n+1}\\ =&\frac 1{n+1}[x^n]H(x)^{n+1}\left(\frac y{(1-H(x))(1-xy)^2}+\frac{H'(x)}{(1-H(x))^2(1-xy)}\right)\\ =&\frac 1{n+1}[x^n]H(x)^{n+1}\left(\frac 1{1-H(x)}\sum_{i=1}ix^{i-1}y^i+\frac{H'(x)}{(1-H(x))^2}\sum_{i=0}(xy)^i\right) \end{aligned} \]

直接提取 \(y^m\) 项系数:

\[\begin{aligned} &[x^ny^m]H(x)^{n+1}\left(\frac 1{1-H(x)}\sum_{i=1}ix^{i-1}y^i+\frac{H'(x)}{(1-H(x))^2}\sum_{i=0}(xy)^i\right)\\ =&[x^n]H(x)^{n+1}\left(\frac{mx^{m-1}}{1-H(x)}+\frac{H'(x)x^m}{(1-H(x))^2}\right)\\ =&[x^{n-m+1}]m\frac{H(x)^{n+1}}{1-H(x)}+[x^{n-m}]\frac{H'(x)H(x)^{n+1}}{(1-H(x))^2} \end{aligned} \]

结束。哦还没结束,我们还不知道 \(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;
}
posted @ 2023-03-12 11:39  gtm1514  阅读(35)  评论(0编辑  收藏  举报