原题条件相当于是(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;
}