Description
某个1~n的排列如果满足:
在1~n-1 这些位置后面将序列断开,使得总可以从右边找到一个数,并且该数不大于左边的所有数,则称该序列为“美妙的”。
给出n,求长度为n的“美妙的序列”的数量。
例如:n为3时有3种
2 3 1
3 1 2
3 2 1
解释:比如 2 3 1
(2) (3 1) 1比2小
(2 3) (1) 1比2小
都满足上面的条件。
3 2 1
(3)(2 1) 1比3小
(32)(1) 1比3小
都满足上面的条件。
而2 1 3不满足,因为(2 1)(3),3比左边所有的数都大。
求长度为n的美妙序列的数量(mod 998244353)
Input
第一行一个数T,表示数据组数(T<=10W)
接下来T行,每行一个数N(N<=10W)
Output
对于每组询问输出答案(mod 998244353)
题解
可以发现,满足题意等价与满足序列
1
1
1到
i
i
i的不为
1
1
1到
i
i
i的一个排列。
于是可以
d
p
dp
dp,设
f
[
i
]
f[i]
f[i]表示长度为
i
i
i时的答案是多少。
转移有
f
[
i
]
=
i
!
−
∑
f
[
j
]
∗
(
i
−
j
)
!
f[i]=i! - \sum {f[j]*(i-j)!}
f[i]=i!−∑f[j]∗(i−j)!
发现右边是一个卷积,移项得。
∑
f
[
j
]
∗
(
i
−
j
)
!
=
i
!
\sum{f[j]*(i-j)!}=i!
∑f[j]∗(i−j)!=i!
然后设
f
(
x
)
=
1
+
1
!
x
+
2
!
x
2
+
.
.
.
f(x)=1+1!x+2!x^2+...
f(x)=1+1!x+2!x2+...
g
(
x
)
=
f
[
0
]
+
f
[
1
]
x
+
f
[
2
]
x
2
+
.
.
.
g(x)=f[0]+f[1]x+f[2]x^2+...
g(x)=f[0]+f[1]x+f[2]x2+...
即两个数列的生成函数。
得到
f
(
x
)
∗
g
(
x
)
+
1
=
g
(
x
)
f(x)*g(x)+1=g(x)
f(x)∗g(x)+1=g(x)
所以得到
f
(
x
)
=
1
−
1
g
(
x
)
f(x)=1-\frac{1}{g(x)}
f(x)=1−g(x)1
用NTT多项式求逆即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN=2000000;
const ll MOD=998244353LL;
ll read(){
ll rt=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){rt=rt*10+ch-'0';ch=getchar();}
return rt;
}
void write(ll num){
if(!num)putchar('0');
static char str[50];
static int len=0;
while(num){str[++len]=num%10+'0';num/=10;}
while(len){putchar(str[len--]);}
putchar('\n');
}
ll ksm(ll x,ll y,ll z){
ll ret=1;
while(y){
if(y&1){ret=(ret*x)%z;}
x=(x*x)%z;
y>>=1;
}
return ret;
}
int bitrev[MAXN];
ll Pinv[MAXN],P[MAXN],Q[MAXN];
void NTT(ll *x,int len,int flag){
for(int i=0;i<len;i++)if(i<bitrev[i]){swap(x[i],x[bitrev[i]]);}
for(int i=1;i<len;i<<=1){
ll wn=ksm(3,(MOD-1)/(i<<1),MOD);
for(int j=0;j<len;j+=(i<<1)){
ll w=1;
for(int k=0;k<i;k++,w=(w*wn)%MOD){
ll a=x[j+k],b=(w*x[j+k+i])%MOD;
x[j+k]=(a+b)%MOD;x[j+k+i]=(a-b+MOD)%MOD;
}
}
}
if(flag==-1){
reverse(x+1,x+len);
ll inv=ksm(len,MOD-2,MOD);
for(int i=0;i<len;i++){
x[i]=(x[i]*inv)%MOD;
}
}
}
void GetInv(int len,ll *x,ll *b){
if(len==1){
b[0]=ksm(P[0],MOD-2,MOD);
// cout<<b[0]<<endl;
return;
}
GetInv((len+1)>>1,x,b);
int L=0,tmp=1,tmpp=2*len;
for(tmp=1;tmp<=tmpp;tmp<<=1)L++;
for(int i=0;i<len;i++)x[i]=P[i];
for(int i=0;i<tmp;i++)bitrev[i]=0;
for(int i=0;i<tmp;i++)bitrev[i]=(bitrev[i>>1]>>1)|((i&1)<<(L-1));
for(int i=len;i<tmp;i++){x[i]=0;b[i]=0;}/*
for(int i=0;i<tmp;i++)cout<<x[i]<<" ";
cout<<endl;
for(int i=0;i<tmp;i++)cout<<b[i]<<" ";
cout<<endl;*/
NTT(x,tmp,233);NTT(b,tmp,233);
for(int i=0;i<tmp;i++){
// b[i]=(2-(x[i]*(b[i]*b[i])%MOD)%MOD+MOD)*b[i]%MOD;
b[i]=(b[i]%MOD * (2-(x[i]*b[i])%MOD))%MOD;
if(b[i]<0)b[i]+=MOD;
}
NTT(b,tmp,-1);/*
for(int i=0;i<len;i++)cout<<b[i]<<" ";
cout<<endl;*/
for(int i=len;i<tmp;i++)b[i]=0;
}
int main(){
P[0]=1;
for(ll i=1;i<100002;i++){
P[i]=(i*P[i-1])%MOD;
// cout<<P[i]<<endl;
}
GetInv(100002,Q,Pinv);
for(int i=0;i<100002;i++){
Pinv[i]=(-Pinv[i])%MOD;
Pinv[i]=(Pinv[i]+MOD)%MOD;
}
Pinv[0]++;
int T;
T=read();
while(T--){
ll t=read();
write(Pinv[t]);
}
return 0;
}