LOJ6402 - yww与校门外的树

链接

原题条件相当于是\(a\)是一个排列,每种排列出现概率随机。

考虑从\(1\to n\)插入排列中,容易观察到只要后面还有空位,那么前缀一定是相连的。

由这个过程可以观察到一些性质:

  • 连通块是一段区间
  • 相邻连通块的最大最小值区间不交(即:合并只有一种方案)

\(F(x)\)是长度为\(i\)的排列组成一个联通块的\(OGF\)\([x^0]F = 0\)),\(T(x) = \sum _i i!x^i\)

容易得到:

\[\begin{aligned} \frac 1 {(1-F)} &= T \\ F &= 1- \frac 1T \end{aligned} \]

\(G = \sum [x^i]F\times ix^i\)

则:

\[ANS = \frac 1 {1-G} \]

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

代码

#include<bits/stdc++.h>
using namespace std;
const int N=4e6+5;
typedef long long ll;
const int mod=998244353,g=3;
int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
int sub(int a,int b){a-=b;return a<0?a+mod:a;}
int mul(int a,int b){return (ll)a*b%mod;}
int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
/* math */

namespace Template_poly{
	typedef vector<int> poly;
	int rev[N];
	poly poly_add(poly A,poly B){
		A.resize(max(A.size(),B.size()));
		for(size_t i=0;i<B.size();i++)A[i]=add(A[i],B[i]);
		return A;
	}
	poly poly_sub(poly A,poly B){
		A.resize(max(A.size(),B.size()));
		for(size_t i=0;i<B.size();i++)A[i]=sub(A[i],B[i]);
		return A;
	}
	void DFT(int *t,int n,int type){
		int l=0;while(1<<l<n)++l;
		for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
		for(int i=0;i<n;i++)if(rev[i]>i)swap(t[rev[i]],t[i]);
		for(int step=1;step<n;step<<=1){
			int wn=qpow(g,(mod-1)/(step<<1));
			for(int i=0;i<n;i+=step<<1){
				int w=1;
				for(int k=0;k<step;k++,w=mul(w,wn)){
					int x=t[i+k],y=mul(t[i+k+step],w);
					t[i+k]=add(x,y),t[i+k+step]=sub(x,y);
				}
			}
		}
		if(type==1)return;
		for(int i=1;i<n-i;i++)swap(t[i],t[n-i]);
		int inv=qpow(n,mod-2);
		for(int i=0;i<n;i++)t[i]=mul(t[i],inv);
	}
	poly NTT(poly A,int n,poly B,int m){
		static poly res,PolA,PolB;
		PolA=A,PolB=B;
		int len=1;while(len < n+m)len<<=1;
		res.resize(len);
		PolA.resize(len),PolB.resize(len);
		DFT(&PolA[0],len,1);DFT(&PolB[0],len,1);
		for(int i=0;i<len;i++) res[i]= mul(PolA[i],PolB[i]);
		DFT(&res[0],len,-1);
		res.resize(n+m-1);
		return res;
	}
	poly NTT(poly A,poly B){
		return NTT(A,A.size(),B,B.size());
	}
	poly poly_inv(poly A,int n){
		if(n==1)return poly(1,qpow(A[0],mod-2));
		int len=1<<((int)ceil(log2(n))+1);
		poly x=poly_inv(A,(n+1)>>1),y;
		x.resize(len),y.resize(len);
		for(int i=0;i<n;i++)y[i]=A[i];
		DFT(&x[0],len,1),DFT(&y[0],len,1);
		for(int i=0;i<len;i++)x[i]=mul(x[i],sub(2,mul(x[i],y[i])));
		DFT(&x[0],len,-1);
		x.resize(n);
		return x;
	}
	poly poly_inv(poly A){
		return poly_inv(A,A.size());
	}
}
using namespace Template_poly;
int n;
poly f,fc;

int main()
{
	cin >> n;
	fc.resize(n+1);
	fc[0] = 1;for(int i=1;i<=n;i++)fc[i] = mul(fc[i-1],i);
	f = poly_inv(fc);
	f[0] = sub(f[0],1);
	for(int i=0;i<=n;i++)f[i] = mod - mul(i, mod - f[i]);
	f[0] = add(f[0],1);
	f = poly_inv(f);
	cout << f[n] << endl;
}


posted @ 2019-09-24 21:11  jerome_wei  阅读(234)  评论(0编辑  收藏  举报