CF1349F2 Slime and Sequences (Hard Version)

题目描述

定义一个正整数序列 p \texttt{p} p,称其是合法的当且仅当对于所有在 p \texttt{p} p中出现过且 > 1 > 1 >1的正整数 k k k,存在 i < j ii<j,满足 p i = k − 1 , p j = k p_i=k-1,p_j=k pi=k1,pj=k

定义 f ( k ) f(k) f(k) k k k在所有长度为 n n n的好序列中的出现次数之和。

∀ k ∈ [ 1 , n ] \forall k\in[1,n] k[1,n] f ( k ) f(k) f(k)

Easy Version( n ≤ 5000 n\leq 5000 n5000)

可证明每个合法序列和一个排列一一对应:

  • 1.考虑怎么把排列对应成一个合法序列:

考虑把排列划分成若干极长的连续下降段,若第 i i i段里有数 x x x,就让 p x = i p_x=i px=i

这样构造的 p p p一定是合法的,否则就说明存在一个 k k k,使得所有 k k k的出现位置都在 k − 1 k-1 k1的出现位置前面,那么这两个连续段应该会变成一个,就矛盾了。

  • 2.一个合法序列对应一个排列

这是显然的,把上述过程逆过来就好了。

因此这是一个双射。

那么对于一个位置 i i i,它对 f ( k ) f(k) f(k)的贡献就是它被划分在第 k k k段的排列数。

对于位置 i i i,若 p i < p i + 1 p_ipi<pi+1,我们称之为一个上升

i i i被划分在第 k k k段的排列数等价与前 i i i个位置恰好有 k − 1 k-1 k1个上升。

设长度为 n n n且有 m m m个上升的排列个数为 d p n , m dp_{n,m} dpn,m,则
f ( k ) = ∑ i = 1 n d p i , k − 1 C n i ( n − i ) ! f(k)=\sum_{i=1}^ndp_{i,k-1}C_n^i(n-i)! f(k)=i=1ndpi,k1Cni(ni)!

d p n , m dp_{n,m} dpn,m的递推是好求的,考虑加入最小的数:

  • 加入后上升个数不变,有 m + 1 m+1 m+1种选择,因为可以填到末尾

  • 加入后上升个数加一,有 n − m n-m nm种选择,因为可以填到开头

总复杂度 O ( n 2 ) O(n^2) O(n2).


#include
using namespace std;
const int N = 5050;
int dp[N][N];
int n;
const int mod = 998244353;
inline int myplus(int a,int b){return (a+b>=mod?a+b-mod:a+b);}
int ans[N],C[N][N],fac[N];
int main()
{
	cin>>n;
	dp[1][0]=1;
	for(int i=1;i<=n;i++)
	for(int j=0;j<=i-1;j++)
	{
		dp[i+1][j]=myplus(dp[i+1][j],1ll*dp[i][j]*(j+1)%mod);
		dp[i+1][j+1]=myplus(dp[i+1][j+1],1ll*dp[i][j]*(i-j)%mod);
	}
	C[0][0]=1;fac[0]=1;
	for(int i=1;i<=n;i++)
	{
		fac[i]=1ll*fac[i-1]*i%mod;
		C[i][0]=1;
		for(int j=1;j<=i;j++)
		C[i][j]=myplus(C[i-1][j-1],C[i-1][j]);
	}
	for(int k=1;k<=n;k++)
	for(int i=1;i<=n;i++)
	ans[k]=myplus(ans[k],1ll*dp[i][k-1]*C[n][i]%mod*fac[n-i]%mod);
	for(int i=1;i<=n;i++)printf("%d ",ans[i]);
	return 0;
}

Hard Version( n ≤ 1 0 5 n\leq 10^5 n105)

上文中的 f n , m f_{n,m} fn,m其实就是欧拉数,记为 E n , m E_{n,m} En,m,其含义为有m个上升的n阶排列数量。

d p dp dp的求法显然不能拓展,考虑更直接的刻画。

二项式反演,记 D n , m D_{n,m} Dn,m表示钦定 m m m个上升,剩下位置随便的方案数。


D n , m = ∑ k = m n ( k m ) E n , k D_{n,m}=\sum_{k=m}^n \binom{k}{m}E_{n,k} Dn,m=k=mn(mk)En,k

E n , m = ∑ k = m n ( − 1 ) k − m ( k m ) D n , k E_{n,m}=\sum_{k=m}^n(-1)^{k-m}\binom{k}{m}D_{n,k} En,m=k=mn(1)km(mk)Dn,k

考虑 D n , m D_{n,m} Dn,m,把连续的上升看成一个连续段,则每个段的方案数唯一,不同段之间是一个二项卷积,一共有 n − m n-m nm个连续段,故:

连续段的EGF: { 0 , 1 , 1 , … … } \lbrace0,1,1,……\rbrace {0,1,1,……},即 e x − 1 e^x-1 ex1

总的EGF: ( e x − 1 ) n − m (e^x-1)^{n-m} (ex1)nm

即: D n , m = n ! [ x n ] ( e x − 1 ) n − m D_{n,m}=n![x^n](e^x-1)^{n-m} Dn,m=n![xn](ex1)nm

E n , m = n ! ∑ k = m n ( − 1 ) k − m ( k m ) [ x n ] ( e x − 1 ) n − k E_{n,m}=n!\sum_{k=m}^n(-1)^{k-m}\binom{k}{m}[x^n](e^x-1)^{n-k} En,m=n!k=mn(1)km(mk)[xn](ex1)nk

E a s y V e r s i o n Easy Version EasyVersion的答案式:
a n s k = ∑ i = 1 n E i , k − 1 ( n i ) ( n − i ) ! ans_k=\sum_{i=1}^nE_{i,k-1}\binom{n}{i}(n-i)! ansk=i=1nEi,k1(in)(ni)!

方便起见,我们改成 a n s k + 1 ans_{k+1} ansk+1,这样右边会整齐一点。
a n s k + 1 = ∑ i = 1 n E i , k ( n i ) ( n − i ) ! = ∑ i = 1 n ( n i ) ( n − i ) i ! ∑ j = k i ( − 1 ) j − k ( j k ) [ x i ] ( e x − 1 ) i − j ! = n ! ∑ i = 1 n ∑ j = k i ( − 1 ) j − k ( j k ) [ x i ] ( e x − 1 ) i − j ! = n ! k ! ∑ j = k n j ! ( − 1 ) j − k ( j − k ) ! ∑ i = j n [ x i ] ( e x − 1 ) i − j ! \begin{aligned} ans_{k+1} &=\sum_{i=1}^nE_{i,k}\binom{n}{i}(n-i)!\\ &=\sum_{i=1}^n\binom{n}{i}(n-i)i!\sum_{j=k}^i(-1)^{j-k}\binom{j}{k}[x^i](e^x-1)^{i-j}!\\ &=n!\sum_{i=1}^n\sum_{j=k}^i(-1)^{j-k}\binom{j}{k}[x^i](e^x-1)^{i-j}!\\ &=\frac{n!}{k!}\sum_{j=k}^n\frac{j!(-1)^{j-k}}{(j-k)!}\sum_{i=j}^n[x^i](e^x-1)^{i-j}!\\ \end{aligned} ansk+1=i=1nEi,k(in)(ni)!=i=1n(in)(ni)i!j=ki(1)jk(kj)[xi](ex1)ij!=n!i=1nj=ki(1)jk(kj)[xi](ex1)ij!=k!n!j=kn(jk)!j!(1)jki=jn[xi](ex1)ij!

S j = ∑ i = j n [ x i ] ( e x − 1 ) i − j ! S_j=\sum_{i=j}^n[x^i](e^x-1)^{i-j}! Sj=i=jn[xi](ex1)ij!

a n s k + 1 = n ! k ! ∑ j = k n j ! ( − 1 ) j − k ( j − k ) ! S j ans_{k+1}=\frac{n!}{k!}\sum_{j=k}^n\frac{j!(-1)^{j-k}}{(j-k)!}S_{j} ansk+1=k!n!j=kn(jk)!j!(1)jkSj

是一个差卷积的形式,可以直接算。

问题就是求出 S j S_j Sj

S j = ∑ i = j n [ x i ] ( e x − 1 ) i − j ! = ∑ i = j n [ x j ] ( e x − 1 x ) i − j ! = ∑ i = 0 n − j [ x j ] ( e x − 1 x ) i ! \begin{aligned} S_j&=\sum_{i=j}^n[x^i](e^x-1)^{i-j}!\\ &=\sum_{i=j}^n[x^j](\frac{e^x-1}{x})^{i-j}!\\ &=\sum_{i=0}^{n-j}[x^j](\frac{e^x-1}{x})^i!\\ \end{aligned} Sj=i=jn[xi](ex1)ij!=i=jn[xj](xex1)ij!=i=0nj[xj](xex1)i!

F ( x ) = e x − 1 x F(x)=\frac{e^x-1}{x} F(x)=xex1

S j = [ x j ] 1 − F ( x ) n − j + 1 1 − F ( x ) S_j=[x^j]\frac{1-F(x)^{n-j+1}}{1-F(x)} Sj=[xj]1F(x)1F(x)nj+1

= [ x j ] ( 1 1 − F ( x ) − F ( x ) n − j + 1 1 − F ( x ) ) =[x^j](\frac{1}{1-F(x)}-\frac{F(x)^{n-j+1}}{1-F(x)}) =[xj](1F(x)11F(x)F(x)nj+1)

左边几乎可以直接算,唯一需要注意的是 1 − F ( x ) 1-F(x) 1F(x)的常数项为0不能直接算,但是根据某些知识

1 F ( x ) × x − 1 × x − 1 = 1 F \frac{1}{F(x)\times x^{-1}}\times x^{-1}=\frac{1}{F} F(x)×x11×x1=F1

因此可以先平移一下,再平移回来。

重点看右边,设为 R j R_j Rj

R j = [ x j ] F ( x ) n − j + 1 1 − F ( x ) = [ x n ] ( x F ( x ) ) n − j + 1 x − x F ( x ) = [ x n ] ( e x − 1 ) n − j + 1 x − e x + 1 R_j=[x^j]\frac{F(x)^{n-j+1}}{1-F(x)}=[x^n]\frac{(xF(x))^{n-j+1}}{x-xF(x)}=[x^n]\frac{(e^x-1)^{n-j+1}}{x-e^x+1} Rj=[xj]1F(x)F(x)nj+1=[xn]xxF(x)(xF(x))nj+1=[xn]xex+1(ex1)nj+1

G ( x ) = e x − 1 , P ( x ) = ln ⁡ ( x + 1 ) G(x)=e^x-1,P(x)=\ln(x+1) G(x)=ex1,P(x)=ln(x+1),则 P ( G ( x ) ) = x P(G(x))=x P(G(x))=x,即 P , G P,G P,G互为复合逆。

[ x n ] ( e x − 1 ) n − j + 1 x − e x + 1 = [ x n ] G ( x ) n − j + 1 x − G ( x ) [x^n]\frac{(e^x-1)^{n-j+1}}{x-e^x+1}=[x^n]\frac{G(x)^{n-j+1}}{x-G(x)} [xn]xex+1(ex1)nj+1=[xn]xG(x)G(x)nj+1

H j ( x ) = x n − j + 1 P ( x ) − x H_j(x)=\frac{x^{n-j+1}}{P(x)-x} Hj(x)=P(x)xxnj+1,则 R j = [ x n ] H j ( G ( x ) ) R_j=[x^n]H_j(G(x)) Rj=[xn]Hj(G(x))

由扩展另类拉格朗日反演得:
R j = [ x n ] H j ( G ( x ) ) = [ x n ] H j ( x ) P ′ ( x ) ( x P ( x ) ) n + 1 = [ x n ] x n − j + 1 P ( x ) − x P ′ ( x ) ( x P ( x ) ) n + 1 = [ x k − 1 ] 1 P ( x ) − x P ′ ( x ) ( x P ( x ) ) n + 1 \begin{aligned} R_j &=[x^n]H_j(G(x))\\ &=[x^n]H^j(x)P'(x)(\frac{x}{P(x)})^{n+1}\\ &=[x^n]\frac{x^{n-j+1}}{P(x)-x}P'(x)(\frac{x}{P(x)})^{n+1}\\ &=[x^{k-1}]\frac{1}{P(x)-x}P'(x)(\frac{x}{P(x)})^{n+1} \end{aligned} Rj=[xn]Hj(G(x))=[xn]Hj(x)P(x)(P(x)x)n+1=[xn]P(x)xxnj+1P(x)(P(x)x)n+1=[xk1]P(x)x1P(x)(P(x)x)n+1

然后就做完了。

注意求逆的时候要先平移一下。

复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include
using namespace std;
typedef unsigned long long ull; 
#define pb push_back
typedef std::vector<int> Poly;
typedef std::pair<int,int> pii;
typedef std::pair<Poly,Poly> ppp;
Poly Pre(Poly A,int L){A.resize(L);return A;}
void Prt(Poly A){for(int x:A)printf("%d ",x);puts("");}
Poly Rev(Poly A){return std::reverse(A.begin(),A.end()),A;}
Poly Shift(Poly A,int L=1){for(int i=L;i<(int)A.size();++i)A[i-L] = A[i];for(int i=max((int)A.size()-L,0);i<(int)A.size();++i)A[i] = 0;return A;}
const int mdig = 18,mod = 998244353,g = 3,maxn = (1<<mdig);
int Pow(int a,int x){int ans = 1,bas = a;while(x){if(x&1)ans = 1ll*ans*bas%mod;bas = 1ll*bas*bas%mod,x >>= 1;}return ans;}
#define getinv(x) Pow(x,mod-2)
const int ivg = Pow(g,mod-2),I = Pow(g,(mod-1)/4);
int gs[2][mdig][maxn>>1];
void NTT(std::vector<int>&A,int N,int op){
static int rev[maxn],flag;static ull tmp[maxn];
if(!flag){flag = 1;for(int op=0;op<2;++op)for(int i=0;i<mdig;++i){int l=(1<<i),w=Pow(op?ivg:g,(mod-1)/(2*l));for(int p=0,c=1;p<l;++p,c=1ll*c*w%mod)gs[op][i][p] = c;}}
for(int i=0;i<N;++i)rev[i] = (rev[i>>1]>>1)|((i&1)*N/2);
for(int i=0;i<N;tmp[i]=A[i],++i)if(i<rev[i])std::swap(A[i],A[rev[i]]);
for(int l=1,d=0;l<N;l*=2,++d){for(int r=0;r<N;r+=(2*l)){int *GS=gs[op][d];ull *tp1=&tmp[l+r],*tp2=&tmp[r];for(int p=0,t;p<l;++p,++GS,++tp1,++tp2)t = 1ll*(*GS)*(*tp1)%mod,(*tp1) = (*tp2)+mod-t,(*tp2) += t;}if(d == 17)for(int i=0;i<N;++i)tmp[i] %= mod;}
for(int i=0,inv=Pow(N,mod-2);i<N;++i)A[i] = tmp[i]*(op?inv:1)%mod;}
Poly Val(int x){Poly ret;ret.pb(x);return ret;}
Poly Mul(Poly A,int x){x = (x%mod+mod)%mod;for(int &v:A)v = 1ll*v*x%mod;return A;}
Poly Der(Poly A){for(int i=0;i<A.size()-1;++i)A[i] = 1ll*A[i+1]*(i+1)%mod;*A.rbegin() = 0;return A;}
Poly Int(Poly A){static int ifac[maxn]={0,1},now=1;if(now < A.size())for(int i=now+1;i<=A.size();++i)ifac[i] = mod-1ll*(mod/i)*ifac[mod%i]%mod;A.pb(0);for(int i=A.size()-1;i;--i)A[i] = 1ll*A[i-1]*ifac[i]%mod;A[0] = 0;return A;}
Poly Pls(Poly A,Poly B){A.resize(max(A.size(),B.size()));for(int i=0;i<B.size();++i)A[i] = (A[i]+B[i])%mod;return A;}
Poly Mns(Poly A,Poly B){A.resize(max(A.size(),B.size()));for(int i=0;i<B.size();++i)A[i] = (A[i]-B[i]+mod)%mod;return A;}
Poly operator +(Poly A,Poly B){return Pls(A,B);}
Poly operator -(Poly A,Poly B){return Mns(A,B);}
Poly operator *(Poly A,int x){return Mul(A,x);}
Poly operator *(int x,Poly A){return Mul(A,x);}
Poly Times(Poly A,Poly B,int Len=-1){int L = 1;Len = ~Len?Len:A.size()+B.size()-1;while(L<A.size()+B.size()-1)L *= 2;A.resize(L),B.resize(L);NTT(A,L,0),NTT(B,L,0);for(int i=0;i<L;++i)A[i] = 1ll*A[i]*B[i]%mod;NTT(A,L,1);	A.resize(Len);return A;	}
Poly Inv(Poly A,int Len=-1){Len = ~Len?Len:A.size();Poly now;now.pb(getinv(A[0]));int dig=1;while(dig<Len){dig *= 4;Poly t1 = Pre(now,dig),t2 = Pre(Pre(A,dig/2),dig);NTT(t1,dig,0),NTT(t2,dig,0);for(int i=0;i<dig;++i)t1[i] = 1ll*t1[i]*t1[i]%mod*t2[i]%mod;NTT(t1,dig,1),now = Mns(Mul(now,2),Pre(t1,dig/=2));}now.resize(Len);return now;}
Poly Ln(Poly A,int Len=-1){Len = ~Len?Len:A.size();Poly ret = Int(Times(Der(A),Inv(A,Len),Len));ret.resize(Len);return ret;} 
Poly Exp(Poly A,int Len=-1){Len = ~Len?Len:A.size();Poly now;now.pb(1);int dig=1;while(dig<Len)dig *= 2,now = Times(now,Mns(Pls(Pre(A,dig),Val(1)),Ln(now,dig)),dig);now.resize(Len);return now;}
Poly Pow(Poly A,int K){return Exp(Mul(Ln(A),K));}
int n,fac[maxn],ifac[maxn],inv[maxn],N;
Poly F,P,G,H;
int main()
{
	scanf("%d",&n),N = n+3;
	fac[0] = ifac[0] = 1;for(int i=1;i<=N;++i)fac[i] = 1ll*fac[i-1]*i%mod;
	ifac[N] = getinv(fac[N]);for(int i=N;i>=2;--i)ifac[i-1] = 1ll*ifac[i]*i%mod;
	inv[1] = 1;for(int i=2;i<=N;++i)inv[i] = mod-1ll*(mod/i)*inv[mod%i]%mod;
	F.resize(N),P.resize(N);for(int i=1;i<N;++i)F[i] = ifac[i],P[i] = 1ll*(i&1?1:mod-1)*inv[i]%mod;
	H = Times(Der(P),Pow(Inv(Shift(P,1)),n+1),N);P[1] = (P[1]-1+mod)%mod;H = Times(Inv(Shift(P,2)),H,N);
	for(int i=0;i<n;++i)H[i] = H[i+1];F = Shift(F,1);G = Times(F,Inv(Shift(Val(1)-F,1)),N);
	for(int i=0;i<n;++i)H[i] = (G[i+1]+mod-H[i])%mod;G.resize(n),H.resize(n);for(int i=0;i<n;++i)G[i] = 1ll*H[i]*fac[i]%mod*(i&1?mod-1:1)%mod;for(int i=0;i<n;++i)H[i] = ifac[i];
	G = Times(Rev(G),H,n);for(int i=0;i<n;++i)printf("%lld ",1ll*(i&1?mod-1:1)*ifac[i]%mod*fac[n]%mod*G[n-i-1]%mod);
	return 0;
}

你可能感兴趣的:(数学——多项式,c++,算法,图论)