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)
Sample Input
1
3
Sample Output
3
题解
这个朴素dp还是很好想的啊
发现没有办法直接计算合法的,用不合法的减去
确定第一个让他不合法的位置,容易发现这个位置前面的值域连续,后面的值域也连续
且都为 [ 1 , i ] [1,i] [1,i]和 [ i + 1 , n ] [i+1,n] [i+1,n]
前面的一定要合法,后面的任意排列可以知道转移
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 [ i ] f[i] f[i]与 0 ! 0! 0!合并了…
显然这是一个卷积形式,考虑如何优化
构造生成函数 f ( x ) = 1 + 1 ! x + 2 ! x 2 + 3 ! x 3 . . . f(x)=1+1!x+2!x^2+3!x^3... f(x)=1+1!x+2!x2+3!x3...
构造生成函数 g ( x ) = f [ 0 ] + f [ 1 ] x + f [ 2 ] x 2 + f [ 3 ] x 3 . . . g(x)=f[0]+f[1]x+f[2]x^2+f[3]x^3... g(x)=f[0]+f[1]x+f[2]x2+f[3]x3...
容易得到
f ( x ) ∗ g ( x ) + 1 = f ( x ) f(x)*g(x)+1=f(x) f(x)∗g(x)+1=f(x)
这个1是用来补足常数项的
移项可知
g ( x ) = 1 − 1 f ( x ) g(x)=1-\frac{1}{f(x)} g(x)=1−f(x)1
这个可以多项式求逆求出
或者你根据 ∑ f [ j ] ∗ ( i − j ) ! = i ! \sum f[j]*(i-j)!=i! ∑f[j]∗(i−j)!=i!可以分治NTT做
还是点技能舒服
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define mod 998244353
using namespace std;
inline int read()
{
int f=1,x=0;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;
}
inline void write(int x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
inline void pr1(int x){write(x);printf(" ");}
inline void pr2(int x){write(x);puts("");}
LL pow_mod(LL a,LL b)
{
LL ret=1;
while(b)
{
if(b&1)ret=ret*a%mod;
a=a*a%mod;b>>=1;
}
return ret;
}
int R[110000*4],L;
void NTT(LL *y,int len,int on)
{
for(int i=0;i<len;i++)if(i<R[i])swap(y[i],y[R[i]]);
for(int i=1;i<len;i<<=1)
{
LL wn=pow_mod(3,(mod-1)/(i<<1));if(on==-1)wn=pow_mod(wn,mod-2);
for(int j=0;j<len;j+=(i<<1))
{
LL w=1;
for(int k=0;k<i;k++)
{
LL u=y[j+k];
LL v=y[j+k+i]*w%mod;
y[j+k]=(u+v)%mod;
y[j+k+i]=(u-v+mod)%mod;
w=w*wn%mod;
}
}
}
if(on==-1)
{
LL temp=pow_mod(len,mod-2);
for(int i=0;i<len;i++)y[i]=(y[i]*temp)%mod;
}
}
LL A[110000*4],G[110000*4],B[110000*4];
void getinv(LL *B,int len)
{
if(len==1){B[0]=pow_mod(A[0],mod-2);return ;}
getinv(B,len>>1);
int ln;L=0;
for(ln=1;ln<=len;ln<<=1)L++;
for(int i=0;i<ln;i++)R[i]=(R[i>>1]>>1)|(i&1)<<(L-1);
for(int i=0;i<len;i++)G[i]=A[i];
for(int i=len;i<ln;i++)G[i]=B[i]=0;
NTT(G,ln,1);NTT(B,ln,1);
for(int i=0;i<ln;i++)B[i]=(B[i]*(2-G[i]*B[i]%mod)+mod)%mod;
NTT(B,ln,-1);
for(int i=len;i<ln;i++)B[i]=0;
}
int main()
{
int length;
for(length=1;length<=100000;length<<=1);
A[0]=1;
for(int i=1;i<length;i++)A[i]=A[i-1]*i%mod;
getinv(B,length);
for(int i=0;i<length;i++)B[i]=(-B[i]+mod)%mod;B[0]++;
int T=read();
while(T--)pr2(B[read()]);
return 0;
}