51Nod-1514 美妙的序列 多项式求逆模板题
51Nod-1514 美妙的序列 多项式求逆模板题
题意
某个序列满足:
从\(1 -(n-1)\)的某个位置断开,可以使得总能从右边找到某个数且该数不大于左边的所有数就称这个序列美妙
问长度\(n\)的美妙的序列方案数
分析
序列不美妙\(\iff\) \(\exist i\geq1,区间[1,i]\)是\([1,i]\)的排列
那么就可以考虑枚举使得序列不美妙的“分割点”,有转移方程
\[dp[n] = n! - \sum_{i=1}^{n-1}dp[i](n-i)!
\]
令
\[G(x) = 0!x^0 + 1!x^1+ 2!x^2...\\
F(x)= 0x^0 + dp[1]x^1 + dp[2]x^2...
\]
有
\[F * G + 1= G\\
F = \frac{G-1}{G}
\]
代码
#include<bits/stdc++.h>
#define pii pair<ll,ll>
#define fi first
#define se second
using namespace std;
typedef long long ll;
inline int rd(){
int x;
scanf("%d",&x);
return x;
}
const int MOD = 998244353;
inline int mul(int a,int b){
int res = (ll)a * b % MOD;
if(res < 0) res += MOD;
return res;
}
inline void add(int &a,int b){
a += b;
if(a >= MOD) a -= MOD;
}
inline void sub(int &a,int b){
a -= b;
if(a < 0) a += MOD;
}
const int maxn = 1e5 + 5;
int a[maxn * 3],b[maxn * 3],c[maxn * 3]; //b:1/(1+f)
int d[maxn * 3]; //d:f
int ans[maxn * 3];
class NTTClass{
public:
static const int MAXL= 21;
static const int MAXN= 1 << MAXL;
static const int root= 3;
static const int MOD= 998244353;
int rev[MAXN];
inline int fast_pow(int a,int b){
int ans=1;
while(b){
if(b & 1) ans = 1ll * ans * a %MOD;
a = (ll)a * a %MOD;
b >>= 1;
}
return ans;
}
inline void transform(int n,int *t,int typ){
for(int i = 0;i < n;i++)
if(i < rev[i]) swap(t[i],t[rev[i]]);
for(int step = 1;step < n;step <<= 1){
int gn = fast_pow(root,(MOD - 1)/(step << 1));
for(int i = 0;i < n;i += (step << 1)){
int g = 1;
for(int j = 0;j < step;j++,g = (ll)g * gn %MOD){
int x = t[i + j],y = (ll)g * t[i + j + step] % MOD;
t[i + j] = (x + y)% MOD;
t[i + j + step]=(x - y + MOD)%MOD;
}
}
}
if(typ == 1)return;
for(int i = 1;i < n / 2;i++) swap(t[i],t[n - i]);
int inv = fast_pow(n,MOD - 2);
for(int i = 0;i < n;i++) t[i] = (ll)t[i] * inv %MOD;
}
inline void ntt(int p,int *A,int *B,int *C){
transform(p,A,1);
transform(p,B,1);
for(int i = 0;i < p;i++)C[i] =(ll)A[i] * B[i] % MOD;
transform(p,C,-1);
}
inline void mul(int *A,int *B,int *C,int n,int m) {
int p = 1,l = 0;
while(p <= n + m)p <<= 1,l++;
//printf("n = %d, m = %d\n",n,m);
for (int i = n + 1;i < p;i++) A[i] = 0;
for (int i = m + 1;i < p;i++) B[i] = 0;
//for (int i=0;i<p;i++) printf("%d ",A[i]);puts("");
//for (int i=0;i<p;i++) printf("%d ",B[i]);puts("");
for(int i = 0;i < p;i++) rev[i] = (rev[i >> 1]>>1) | ((i & 1) << (l - 1));
ntt(p,A,B,C);
//puts("C:");for (int i=0;i<p;i++) printf("%d ",C[i]);puts("");
}
inline void getInv(int deg,int *A,int *B){
if(deg == 1) {
B[0] = fast_pow(A[0],MOD - 2);
return;
}
getInv((deg + 1) >> 1,A,B);
int p = 1,l = 0;
while(p < (deg << 1)) p <<= 1,l++;
for(int i = 0;i < p;i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
for(int i = 0;i < deg;i++) c[i] = A[i];
for(int i = deg;i < p;i++) c[i] = 0;
transform(p,c,1);
transform(p,B,1);
for(int i = 0;i < p;i++)
B[i] = (ll)(2 - (ll)c[i] * B[i] % MOD + MOD) % MOD * B[i] % MOD;
transform(p,B,-1);
for(int i = deg;i < p;i++) B[i] = 0;
}
}NTT;
int main(){
a[0] = 1;
for(int i = 1;i < maxn;i++)
a[i] = mul(a[i - 1],i);
for(int i = 1;i < maxn;i++)
d[i] = a[i];
d[0] = 0;
NTT.getInv(maxn,a,b);
NTT.mul(b,d,ans,maxn - 1,maxn - 1);
int T = rd();
while(T--)
printf("%d\n",ans[rd()]);
}