HDU 5322 Hope

HDU 5322 Hope

考虑$dp[n]$表示 长度为$n$的所有排列的答案。

首先,对于一个排列来说,如果最大值在$i$位置,那么前$i - 1$个数必然与$i$在一个联通块,且必然不会与$i$后面的数字在一个连通块。

那么考虑一种常用的排列的处理技巧,考虑将$n$插入$1 \dots n-1$的一个排列,比如插入的位置是$i$那么$i + 1 \dots n$相当于又是一个排列,而$1 \dots i - 1$的方案数是$A_{n-1}^{i-1}$所以答案就是

$dp[n] = \displaystyle \sum_{i=1}^n A_{n-1}^{i-1} i^2 dp[n - i]$

这个式子看起来就很分治FFT。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
#define P 998244353
#define MAXN (1 << 19) + 12
int n;
int a[MAXN];
int Pow(int x,int y) {
int res=1;
while(y) {
if(y&1) res=res*(ll)x%P;
x=x*(ll)x%P,y>>=1;
}
return res;
}
int wn[2][MAXN];
void getwn(int l) {
for(int i=1;i<(1<<l);i<<=1) {
int w0=Pow(3,(P-1)/(i<<1)),w1=Pow(3,P-1-(P-1)/(i<<1));
wn[0][i]=wn[1][i]=1;
for(int j=1;j<i;++j)
wn[0][i+j]=wn[0][i+j-1]*(ll)w0%P,
wn[1][i+j]=wn[1][i+j-1]*(ll)w1%P;
}
}
int rev[MAXN];
void getr(int l) { for(int i=1;i<(1<<l);++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l-1); }
void NTT(int *A,int len,int f) {
for(int i=0;i<len;++i) if(rev[i]<i) swap(A[i],A[rev[i]]);
for(int l=1;l<len;l<<=1)
for(int i=0;i<len;i+=(l<<1))
for(int k=0;k<l;++k) {
int t1=A[i+k],t2=A[i+l+k]*(ll)wn[f][l+k]%P;
A[i+k]=(t1+t2)%P;
A[i+l+k]=(t1-t2+P)%P;
}
if( f == 1 ) for(int inv=Pow(len,P-2),i=0;i<len;++i) A[i]=A[i]*(ll)inv%P;
}
int f[MAXN];
int A[MAXN] , B[MAXN];
int J[MAXN] , invJ[MAXN];
void CDQ(int *a,int *b,int l,int r){
if( l == r ) return;
int m = l + r >> 1;
CDQ( a , b , l , m );
int p = 1 , len = 0;
while( p <= ( r - l + 1 ) * 2 ) p <<= 1 , ++ len;
getr( len ) , getwn( len );
for( int i = 0 ; i < p ; ++i ) A[i] = B[i] = 0;
for( int i = l ; i <= m ; ++i ) A[i - l] = 1ll * a[i] * invJ[i] % P;
for( int i = 0 ; i <= r - l ; ++i ) B[i] = 1ll * i * i % P;
NTT( A , p , 0 ) , NTT( B , p , 0 );
for( int i = 0 ; i < p ; ++i ) A[i] = 1ll * A[i] * B[i] % P;
NTT( A , p , 1 );
for( int i = m + 1 ; i <= r ; ++i ) a[i] = ( a[i] + 1ll * J[i - 1] * A[i-l] % P ) % P;
CDQ( a , b , m + 1 , r );
}
int main() {
J[0] = invJ[0] = 1;
for( int i = 1 ; i < MAXN ; ++ i ) J[i] = 1ll * J[i - 1] * i % P , invJ[i] = Pow( J[i] , P - 2 );
f[0] = 1;
CDQ( f , a , 0 , 100006 );
int x;
while( cin >> x ) printf("%d\n",f[x]);
}
文章作者: yijan
文章链接: https://yijan.co/old67/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yijan's Blog