Codeforces Round #641 Div1.F Slime and Sequences 中文题解

Caro23333

2020-04-30 00:37:03

Solution

### Slime and Sequences 中文题解 **UPD:你可以在这里看到 Elegia 的题解:https://blog.csdn.net/EI_Captain/article/details/106122006** #### Easy Version 首先我们可以将长度为 $n$ 的好序列和长度为 $n$ 的排列一一对应。设一个长度为 $n$ 的排列为 $a_1,a_2,\cdots,a_n$ ,则在每个 $a_i,a_{i+1}$ 之间填入大于号或小于号,则 $p_{a_i}$ 的值即为 $a_1,a_2,\cdots ,a_i$ 之间小于号的数量加 $1$ ,不难验证这是一个 $S$ 与所有排列的集合的一个一一对应。 设 $d_{i,j}$ 为在长度为 $i+1$ 的排列中在 $a_1,a_2,\cdots ,a_{i+1}$ 至少有 $j$ 个小于号的方案数,则将每一段连续的小于号当成一段,对确定的数的集合填入这一段中只有唯一一种填法,而 $d_{i,j}$ 中有 $i-j+1$ 段,所以 $d_{i,j}$ 的值即为将 $n$ 个数分成有区别的 $i-j +1$ 组的方案数,由第二类斯特林数的 $EGF$ 可以知道: $d_{i,j}=(i+1)![z^{i+1}](e^z-1)^{i-j+1}$ 。我们也可以用类似第二类斯特林数的dp求出每个 $d_{i,j}$ 的值。 求答案时,对每个 $1\leq i\leq n$ ,我们考虑每个位置上的贡献,即对于每个 $1$ 到 $n$ 的排列,找每个位置前面有 $i-1$ 个小于号的方案数,可以列出式子: $$ans_{i+1}=\sum\limits_{x=0}^{n-1}\sum\limits_{y=i}^x (-1)^{y-i} {y\choose i}d_{x,y}\frac{n!}{(x+1)!}$$ $$=\frac {n!}{i!}\sum\limits_{x=0}^{n-1}\sum\limits_{y=i}^x (-1)^{y-i}\frac{y!d_{x,y}}{(y-i)!(x+1)!} $$ $$=\frac{n!}{i!} \sum\limits_{y=i}^{n-1}\frac{(-1)^{y-i}y!}{(y-i)!}\sum\limits_{x=y}^{n-1}\frac{d_{x,y}}{(x+1)!}$$ $$=\frac {n!}{i!}\sum\limits_{y=i}^{n-1} \frac{(-1)^{y-i}y!}{(y-i)!} \sum\limits_{x=y}^{n-1}[z^{x+1}](e^z-1)^{x-y+1}$$ 如果对每个 $y$ 求出了 $\sum\limits_{x=y}^{n-1}[z^{x+1}](e^z-1)^{x-y+1}$ ,即可以用一次卷积求出所有 $ans_i$ 的值。 由于存在简单的 $O(n^2)$ 算法来对每个 $y$ 求出上式的值,所以如果我们用 $O(n^2)$ 的dp求 $d_{x,y}$ ,我们就得到了一个 $O(n^2)$ 的做法,可以通过简单版 (其他形式的dp也可以得到这个复杂度,我们在这里仅给出可以导向正解的做法)。 #### Hard Version 接下来考虑如何在低于 $O(n^2)$ 的时间内求出这一系列的值。 $$\sum\limits_{x=y}^{n-1}[z^{x+1}](e^z-1)^{x-y+1}=\sum\limits_{x=y+1}^n[z^x](e^z-1)^{x-y}$$ $$=[z^y]\sum\limits_{x=y+1}^n(\frac{e^z-1}z)^{x-y}=[z^y]\sum\limits_{x=1}^{n-y}(\frac{e^z-1}z)^x$$ 设 $F=\frac{e^z-1}z$ ,现在我们想要对每个 $0\leq i\leq n-1$ ,求出 $[z^i]\sum\limits_{k=1}^{n-i}F^k$ 。 $$[z^i]\sum\limits_{k=1}^{n-i}F^k =[z^i]\frac 1{1-F}-[z^i]\frac{F^{n-i+1}}{1-F}$$ 我们可以用一次多项式求逆求出 $[z^i]\frac 1{1-F}$ ,现在只需处理后面的一项。 $$[z^i]\frac{F^{n-i+1}}{1-F}=[z^{n+1}]\frac{(zF)^{n-i+1}}{1-F}$$ 设 $w(z)=zF(z)$ ,$\phi (z)$ 满足 $\frac{w(z)}{\phi (w(z))}=z$ ,则 $\frac{zF(z)}{\phi (w(z))}=z$ ,即 $F=\phi (w)$ 原式 $=[z^{n+1}u^{n-i+1}]\sum\limits_{k=0}^\infty \frac{(uzF)^k}{1-F}=[z^{n+1}u^{n-i+1}] \frac 1{1-\phi (w)}\frac 1{1-uw}$ 由拉格朗日反演可得 $$=[u^{n-i+1}]\frac 1{n+1} [z^n] ((\frac 1{1-\phi z}\frac 1{1-uz})'\cdot \phi (z)^{n+1})$$ $$=\frac 1{n+1} [z^nu^{n-i+1}] (\phi (z)^{n+1}\frac{u+\phi'(z)-u\phi(z)-uz\phi'(z)}{(1-\phi (z))^2(1-uz)^2})$$ $$=\frac 1{n+1} [z^nu^{n-i+1}] (\phi(z)^{n+1}(\frac {u}{(1-\phi (z))(1-uz)^2}+\frac {\phi'(z)}{(1-\phi (z))^2(1-uz)}))$$ $$=\frac 1{n+1}[z^nu^{n-i+1}](\phi (z)^{n+1}(\frac 1{1-\phi(z)}\sum\limits_{k=0}^\infty (k+1)z^ku^{k+1}+\frac{\phi'(z)}{(1-\phi (z))^2}\sum\limits_{k=0}^\infty z^ku^k))$$ $$=\frac 1{n+1}[z^n](\phi (z)^{n+1}(\frac{(n-i+1)z^{n-i}}{1-\phi (z)}+\frac{\phi'(z)z^{n-i+1}}{(1-\phi(z))^2}))$$ $$=\frac 1{n+1}([z^i](\phi(z)^{n+1}\frac{n-i+1}{1-\phi(z)})+[z^{i-1}](\phi(z)^{n+1}\frac{\phi'(z)}{(1-\phi(z))^2}))$$ 我们可以在 $O(n\log n)\ \sim \ O(n\log ^2n)$ 的时间内(取决于你如何求多项式exp)求出 $\phi(z)^{n+1}\frac{n-i+1}{1-\phi(z)}$ 和 $\phi(z)^{n+1}\frac{\phi'(z)}{(1-\phi(z))^2}$ ,从而得出答案。 总复杂度为 $O(n\log n)\ \sim\ O(n\log ^2n) $。 Problem and Tutorial by he_____he Solution(Hard Version) by Elegia Easy Version Code: ```cpp #include<bits/stdc++.h> #define pb push_back #define mp make_pair #define fi first #define se second using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> pll; template <typename T> bool chkmax(T &x,T y){return x<y?x=y,true:false;} template <typename T> bool chkmin(T &x,T y){return x>y?x=y,true:false;} int readint(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int cys=998244353; int n; ll fac[5005],inv[5005],d[5005][5005],ans[5005]; ll qpow(ll x,ll p){ ll ret=1; for(;p;p>>=1,x=x*x%cys) if(p&1) ret=ret*x%cys; return ret; } int main(){ n=readint(); d[0][0]=fac[0]=inv[0]=1; for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%cys; inv[n]=qpow(fac[n],cys-2); for(int i=n-1;i>=1;i--) inv[i]=inv[i+1]*(i+1)%cys; for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) d[i][j]=(d[i-1][j-1]*(i-j+1)+d[i-1][j]*j)%cys; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) ans[i]=(ans[i]+d[j][i]*inv[j])%cys; for(int i=1;i<=n;i++) printf("%lld ",ans[i]*fac[n]%cys); printf("\n"); return 0; } ``` Hard Version Code: ```cpp #include<bits/stdc++.h> #define pb push_back #define mp make_pair #define fi first #define se second using namespace std; typedef long long ll; typedef unsigned long long ull; typedef vector<ll> vi; typedef pair<int,int> pii; typedef pair<ll,ll> pll; template <typename T> bool chkmax(T &x,T y){return x<y?x=y,true:false;} template <typename T> bool chkmin(T &x,T y){return x>y?x=y,true:false;} int readint(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int cys=998244353,g=3,invg=(cys+1)/3; int n; ll ni[200015],fac[200015],inv[200015],tw[200005]; int mod(int x){return x>=cys?x-cys:x;} ll qpow(ll x,ll p){ ll ret=1; for(;p;p>>=1,x=x*x%cys) if(p&1) ret=ret*x%cys; return ret; } vi operator+(vi a,vi b){ vi ret(max(a.size(),b.size())); for(int i=0;i<ret.size();i++) ret[i]=mod((i<a.size()?a[i]:0)+(i<b.size()?b[i]:0)); return ret; } vi operator-(vi a,vi b){ vi ret(max(a.size(),b.size())); for(int i=0;i<ret.size();i++) ret[i]=mod((i<a.size()?a[i]:0)+cys-(i<b.size()?b[i]:0)); return ret; } vi operator*(vi a,ll b){ for(int i=0;i<a.size();i++) a[i]=1ll*a[i]*b%cys; return a; } vi operator>>(vi a,int b){ for(int i=0;i<a.size()-b;i++) a[i]=a[i+b]; a.resize(a.size()-b); return a; } namespace poly{ int N,l; int A[1100000],B[1100000],r[1100000],pre1[20][600000],pre2[20][600000]; void pre(){ for(int i=1,r=0;i<(1<<19);i<<=1,r++){ int w=1,wn=qpow(g,(cys-1)/(i<<1)); for(int j=0;j<i;j++,w=1ll*w*wn%cys) pre1[r][j]=w; } for(int i=1,r=0;i<(1<<19);i<<=1,r++){ int w=1,wn=qpow(invg,(cys-1)/(i<<1)); for(int j=0;j<i;j++,w=1ll*w*wn%cys) pre2[r][j]=w; } } void ntt(int *A,int N,int f){ for(int i=0;i<N;i++) if(i<r[i]) swap(A[i],A[r[i]]); for(int i=1,r=0;i<N;i<<=1,r++){ for(int j=0;j<N;j+=(i<<1)){ for(int k=j;k<j+i;k++){ int x=A[k],y=1ll*A[k+i]*(f>0?pre1[r][k-j]:pre2[r][k-j])%cys; A[k]=mod(x+y); A[k+i]=mod(x+cys-y); } } } if(f<0){ int invn=qpow(N,cys-2); for(int i=0;i<N;i++) A[i]=1ll*A[i]*invn%cys; } } void init(int t){ N=1,l=0; for(;N<t;N<<=1) l++; for(int i=0;i<N;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1)); } void getmul(){ ntt(A,N,1); ntt(B,N,1); for(int i=0;i<N;i++) A[i]=1ll*A[i]*B[i]%cys; ntt(A,N,-1); } vi mul(vi a,vi b){ init(a.size()+b.size()); for(int i=0;i<N;i++) A[i]=i<a.size()?a[i]:0; for(int i=0;i<N;i++) B[i]=i<b.size()?b[i]:0; getmul(); vi ret(a.size()+b.size()-1); for(int i=0;i<ret.size();i++) ret[i]=A[i]; return ret; } vi polyinv(vi a,int l){ if(l==1) return vi(1,qpow(a[0],cys-2)); a.resize(l); vi b=polyinv(a,(l+1)/2); init(l<<1); for(int i=0;i<N;i++) A[i]=i<l?a[i]:0; for(int i=0;i<N;i++) B[i]=i<(l+1)/2?b[i]:0; ntt(A,N,1); ntt(B,N,1); for(int i=0;i<N;i++) A[i]=1ll*A[i]*B[i]%cys*B[i]%cys; ntt(A,N,-1); vi t=b*2; t.resize(l); for(int i=0;i<l;i++) t[i]=mod(t[i]+cys-A[i]); return t; } vi polydiff(vi a){ for(int i=0;i<a.size()-1;i++) a[i]=1ll*(i+1)*a[i+1]%cys; a.resize(a.size()-1); return a; } vi polyint(vi a){ a.resize(a.size()+1); for(int i=a.size()-1;i>=1;i--) a[i]=1ll*a[i-1]*ni[i]%cys; a[0]=0; return a; } vi polyln(vi a,int l){ return polyint(mul(polydiff(a),polyinv(a,l))); } vi polyexp(vi a,int l){ if(l==1) return vi(1,1); a.resize(l); vi b=polyexp(a,(l+1)/2); init(l<<1); vi t=mul(b,vi(1,1)-polyln(b,l)+a); t.resize(l); return t; } vi polypow(vi a,int l,int k){ return polyexp(polyln(a,l)*k,l); } } vi getans(){ vi f(0); for(int i=0;i<=n+1;i++) f.push_back(inv[i+1]); vi tmp=poly::mul(f,poly::polyinv((vi(1,1)-f)>>1,n+1)); vi tw(0); tw.resize(n); for(int i=0;i<n;i++) tw[i]=tmp[i+1]; vi h(0); h.push_back(1),h.push_back(1); h=poly::polyinv(poly::polyln(h,n+3)>>1,n+2); vi g=poly::polyinv((vi(1,1)-h)>>1,n+1); vi ph=poly::polypow(h,n+1,n+1); vi t1=poly::mul(g,ph); vi tmp1=poly::mul(poly::polydiff(h),ph); tmp1.resize(n+1); vi tmp2=poly::mul(g,g); tmp2.resize(n+1); vi t2=poly::mul(tmp1,tmp2); for(int i=0;i<n;i++) tw[i]=mod(tw[i]+cys-ni[n+1]*mod(t1[i+1]*(n-i+1)%cys+t2[i+1])%cys); for(int i=0;i<n;i++) tw[i]=tw[i]*fac[i]%cys; reverse(tw.begin(),tw.end()); tmp.clear(); for(int i=0;i<n;i++) tmp.push_back(i&1?cys-inv[i]:inv[i]); tw=poly::mul(tw,tmp); tw.resize(n); reverse(tw.begin(),tw.end()); return tw; } int main(){ poly::pre(); n=readint(); fac[0]=inv[0]=1; for(int i=1;i<=n+5;i++) fac[i]=fac[i-1]*i%cys; inv[n+5]=qpow(fac[n+5],cys-2); for(int i=n+4;i>=1;i--) inv[i]=inv[i+1]*(i+1)%cys; for(int i=1;i<=n+5;i++) ni[i]=inv[i]*fac[i-1]%cys; vi res=getans(); for(int i=0;i<n;i++) printf("%lld ",res[i]*fac[n]%cys*inv[i]%cys); printf("\n"); return 0; } ```