LOJ6402

链接

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

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

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

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

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

容易得到:

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

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

则:

[ANS = frac 1 {1-G} ]

复杂度(O(nlog 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;
}


原文地址:https://www.cnblogs.com/weiyanpeng/p/11581095.html