Loading

P7438 更简单的排列计数 题解

前置芝士:伯努利数等幂求和。其中伯努利数 \(B_i\) 的生成函数为 \(\frac{x}{e^x-1}\)


首先这种逆序对有个套路的 dp:令 \(f_{i,j}\) 表示填了前 \(i\) 个数,逆序对为 \(j\),这时排列的 \(val_{\pi}\) 的乘积之和。

有转移:\(f_{i,j}=\sum\limits_{k=0}^{i-1} f_{i-1,j-k}i^k\),初始 \(f_{0,0}=1\)

看到出题人为卡老师想到多项式。令 \(f_n(x)=\sum\limits_{i=0}^m f_{n,i}x^i\),则转移变成:\(f_n(x)=\sum\limits_{k=0}^{n-1} f_{n-1}(x)x^kn^k=\dfrac{f_{n-1}(x)(1-(nx)^n)}{1-nx}\)

于是 \(f_n(x)=\prod\limits_{i=1}^n \dfrac{1-(ix)^i}{1-ix}\),要求其 \(0\sim m\) 次项。

上面:

\(\prod\limits_{i=1}^n (1-(ix)^i)=\exp(\sum\limits_{i=1}^n \ln(1-(ix)^i))=\exp\left(-\sum\limits_{i=1}^n\sum\limits_{j=1}^m\dfrac{(ix)^{ij}}{j}\right)\)

由于只需求其 \(0\sim m\) 次项,于是枚举 \(i,j\) 的复杂度为 \(O(m\log m)\)。总复杂度 \(O(m\log m)\),因为实现精细能规避快速幂。注意 \(i\) 的枚举范围时 \(1\sim \min(n,m)\)

下面:

\(\prod\limits_{i=1}^n (1-ix)^{-1}=\exp(-\sum\limits_{i=1}^n \ln(1-ix))=\exp\left(\sum\limits_{i=1}^n\sum\limits_{j=1}^m\dfrac{(ix)^j}{j}\right)\)

考虑令 \(\exp\) 里面的式子为 \(f(x)\),则 \(f(x)=\sum\limits_{j=1}^m \dfrac{x^j}{j}\sum\limits_{i=1}^n i^j\)

注意到里面为等幂求和,有:\(\sum\limits_{i=1}^n i^j=\frac{1}{j+1}\sum\limits_{i=0}^j\binom{j+1}{i}B_i(n+1)^{j+1-i}\)

于是 \(f(x)=\sum\limits_{j=1}^m \dfrac{x^j}{j(j+1)}\sum\limits_{i=0}^j(j+1)!\times \dfrac{B_i (n+1)^{j+1-i}}{i!(j+1-i)!}=\sum\limits_{j=1}^m x^j(j-1)!\sum\limits_{i=0}^j\dfrac{B_i}{i!}\times \dfrac{(n+1)^{j+1-i}}{(j+1-i)!}\)

\(a_i=\dfrac{B_i}{i!},b_i=\dfrac{(n+1)^{i+1}}{(i+1)!}\),则把 \(a,b\) 卷积就是后半部分,最后第 \(j\) 项系数乘个 \((j-1)!\) 即可。


注意到我们已经把分母 \(-1\) 次方了,于是最后求出的分子分母两个多项式做一个卷积即可,复杂度 \(O(m\log m)\),常数较大。

代码:

#include<bits/stdc++.h>
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
#define LL long long
using namespace std;
const int mod=998244353,N=4e6+5;
int n,m,Bo[N],a[N],b[N],c[N],w[N],jc[N],inv[N],I[N],mmax;
inline int rd()
{
    int x=0,zf=1;char ch=getchar();
    while(ch<'0'||ch>'9') (ch=='-')and(zf=-1),ch=getchar();
    while(ch>='0'&&ch<='9') x=((x<<3)+(x<<1)+ch-'0')%mod,ch=getchar();
    return x*zf;
}
inline void wr(int x)
{
    if(x==0) return putchar('0'),putchar(' '),void();
    int num[35],len=0;
    while(x) num[++len]=x%10,x/=10;
    for(int i=len;i>=1;i--) putchar(num[i]+'0');
    putchar(' ');
}
inline int bger(int x){return x|=x>>1,x|=x>>2,x|=x>>4,x|=x>>8,x|=x>>16,x+1;}
inline int md(int x){return x>=mod?x-mod:x;}
inline int yy(int x){if(x&1) return (x+mod)>>1;return x>>1;}
inline int ksm(int x,int p){int s=1;for(;p;(p&1)&&(s=1ll*s*x%mod),x=1ll*x*x%mod,p>>=1);return s;}
inline void dao(int *a,int n){for(int i=1;i<n;i++) a[i-1]=1ll*i*a[i]%mod;a[n-1]=0;}
inline void ji(int *a,int n){for(int i=n-1;i>=1;i--) a[i]=1ll*ksm(i,mod-2)*a[i-1]%mod;a[0]=0;}
inline void init(int mmax)
{
	for(int i=1,j,k;i<mmax;i<<=1)
		for(w[j=i]=1,k=ksm(3,(mod-1)/(i<<1)),j++;j<(i<<1);j++)
			w[j]=1ll*w[j-1]*k%mod;
}
inline void DNT(int *a,int mmax)
{
	for(int i,j,k=mmax>>1,L,*W,*x,*y,z;k;k>>=1)
		for(L=k<<1,i=0;i<mmax;i+=L)
			for(j=0,W=w+k,x=a+i,y=x+k;j<k;j++,W++,x++,y++)
				*y=1ll*(*x+mod-(z=*y))* *W%mod,*x=md(*x+z);
}
inline void IDNT(int *a,int mmax)
{
	for(int i,j,k=1,L,*W,*x,*y,z;k<mmax;k<<=1)
		for(L=k<<1,i=0;i<mmax;i+=L)
			for(j=0,W=w+k,x=a+i,y=x+k;j<k;j++,W++,x++,y++)
				z=1ll* *W* *y%mod,*y=md(*x+mod-z),*x=md(*x+z);
	reverse(a+1,a+mmax);
	for(int inv=ksm(mmax,mod-2),i=0;i<mmax;i++) a[i]=1ll*a[i]*inv%mod;
}
inline void NTT(int *a,int *b,int n,int m)
{
	mmax=bger(n+m);init(mmax);
	DNT(a,mmax);DNT(b,mmax);
	for(int i=0;i<mmax;i++) a[i]=1ll*a[i]*b[i]%mod;
	IDNT(a,mmax);
}
void INV(int num,int *a,int *b)
{
	if(num==1) return b[0]=ksm(a[0],mod-2),void();INV((num+1)>>1,a,b);
	int mmax=bger(num<<1);init(mmax);static int c[N];
	for(int i=0;i<num;i++) c[i]=a[i];for(int i=num;i<mmax;i++) c[i]=0;DNT(c,mmax);DNT(b,mmax);
	for(int i=0;i<mmax;i++) b[i]=1ll*(2-1ll*c[i]*b[i]%mod+mod)%mod*b[i]%mod;IDNT(b,mmax);
	for(int i=num;i<mmax;i++) b[i]=0;
}
inline void Ln(int *a,int n){static int b[N];for(int i=0;i<bger(n<<1);i++) b[i]=0;INV(n,a,b);dao(a,n);NTT(a,b,n,n);ji(a,n);for(int i=n;i<bger(n<<1);i++) a[i]=0;}
inline void Exp(int *a,int *b,int n)
{
	if(n==1) return b[0]=1,void();
	Exp(a,b,(n+1)>>1);static int c[N];for(int i=0;i<bger(n<<1);i++) c[i]=0;
	for(int i=0;i<n;i++) c[i]=b[i];Ln(c,n);
	for(int i=0;i<n;i++) c[i]=md(mod-c[i]+a[i]);c[0]=md(c[0]+1);
	NTT(b,c,n,n);for(int i=n;i<bger(n<<1);i++) b[i]=0;
}
int main()
{
	n=rd();m=rd()+1;for(int i=jc[0]=1;i<=m;i++) jc[i]=1ll*jc[i-1]*i%mod;
	inv[m]=ksm(jc[m],mod-2);for(int i=m-1;~i;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
	for(int i=0;i<m;i++) a[i]=inv[i+1],I[i]=ksm(i,mod-2);INV(m,a,Bo);
	for(int i=0;i<m;i++) a[i]=Bo[i],b[i]=1ll*ksm(n+1,i+1)*inv[i+1]%mod;
	NTT(a,b,m-1,m-1);for(int i=m;i<mmax;i++) a[i]=b[i]=0;
    a[0]=b[0]=0;for(int i=1;i<m;i++) a[i]=1ll*a[i]*jc[i-1]%mod,b[i]=0;
	Exp(a,b,m);for(int i=0;i<mmax;i++) a[i]=0;
	for(int i=1;i<min(m,n+1);i++) for(int j=1,w=ksm(i,i),s=w;j*i<m;j++,s=1ll*s*w%mod) a[i*j]=(a[i*j]+1ll*s*I[j])%mod;
	for(int i=1;i<m;i++) a[i]=mod-a[i];Exp(a,c,m);NTT(b,c,m-1,m-1);
	for(int i=0;i<m;i++) wr(b[i]);
	return 0;
}
posted @ 2023-08-12 09:41  HaHeHyt  阅读(21)  评论(0编辑  收藏  举报