Codeforces960G Bandit Blues 【Stirling Number】【FFT】

Topic meaning:

  Find the number of permutations of length n that satisfy A smaller than any previous number and B smaller than any subsequent number.

Topic Analysis:

  First write the recursion formula, let s(n,k) denote a permutation of length n, and there are k numbers smaller than the previous number.

  We assume that the newly added number is 1, then s(n,k)=s(n-1,k-1)+(n-1)*s(n,k).

  This formula is the recurrence formula of Stirling numbers of the first kind.

  Use h(n, a, b) to represent the number of permutations that satisfy the conditions given by the question.

  Get h(n,a,b)=Σs(k,a-1)*s(nk-1,b-1)*C(n-1,k). The intuitive understanding is to divide the original arrangement into two parts from the highest point, combine the two parts and multiply them.

  Thus we find h(n,a,b)=s(n-1,a+b-2)*C(a+b-2,a-1). This is actually to give a permutation of a+b-2, and then select the required points and put them on the right. We don't need to consider the redundant points, because their permutations have been calculated.

  Since the unsigned Stirling numbers of the first kind correspond to the coefficients of ascending powers, construct x(x+1)(x+2)...(x+n-1), and its x^k coefficients are equal to s( n,k) value, since the highest term coefficient is 1, so divide and conquer FFT.

Code:

  

 1 #include<bits/stdc++.h>
 2 #pragma GCC optimize(2)
 3 using namespace std;
 4 
 5 const int mod = 998244353;
 6 const int gg = 3;
 7 
 8 int n,a,b;
 9 
10 vector<int> res[205000];
11 
12 int up[405000];
13 
14 int ord[405000];
15 
16 int fast_pow(int now,int pw){
17     if(pw == 0) return 1;
18     if(pw == 1) return now;
19     int z = fast_pow(now,pw/2);
20     z = (1ll*z*z)%mod;
21     if(pw & 1){z= (1ll*z*now)%mod;}
22     return z;
23 }
24 
25 void fft(int now,int len,int f){
26     for(int i=0;i<len;i++) if(i<ord[i]) swap(res[now][i],res[now][ord[i]]);
27     for(int i=1;i<len;i<<=1){
28     int wn = fast_pow(gg,(mod-1)/(i<<1));
29     if(f == -1) wn = fast_pow(wn,mod-2);
30     for(int j=0;j<len;j+=(i<<1)){
31         for(int k=0,w=1;k<i;k++,w = (1ll*w*wn)%mod){
32         int x = res[now][j+k],y = (1ll*w*res[now][j+k+i])%mod;
33         res[now][j+k] = (x+y)%mod;
34         res[now][j+k+i] = (x-y+mod)%mod;
35         }
36     }
37     }
38     if(f == -1){
39     int iv = fast_pow(len,mod-2);
40     for(int i=0;i<len;i++) res[now][i] = (1ll*res[now][i]*iv)%mod;
41     }
42 }
43 
44 void multi(int p1,int p2){
45     int n1 = res[p1].size()-1,n2 = res[p2].size()-1;
46     int len = 1,om = 0;
47     while(len <= (n1+n2+1))len<<=1,om++;
48     for(int i=n1+1;i<len;i++) res[p1].push_back(0);
49     for(int i=n2+1;i<len;i++) res[p2].push_back(0);
50     for(int i=0;i<len;i++) ord[i] = (ord[i>>1]>>1)+((i&1)<<om-1);
51     fft(p1,len,1);fft(p2,len,1);
52     for(int i=0;i<len;i++){
53     res[p1][i] = (1ll*res[p1][i]*res[p2][i])%mod;
54     if(res[p1][i] < 0) res[p1][i]+=mod;
55     }
56     fft(p1,len,-1);
57     res[p2].clear();
58 }
59 
60 void divide(int l,int r,int now){
61     if(l == r) {up[now] = l;return;}
62     int mid = (l+r)/2;
63     divide(l,mid,now<<1);
64     divide(mid+1,r,now<<1|1);
65     multi(up[now<<1],up[now<<1|1]);
66     up[now] = up[now<<1];
67 }
68 
69 void work(){
70     if(a == 0 && b == 0){puts("0");return;}
71     if(n == 1){if(a+b==2)puts("1"); else puts("0"); return;}
72     int c = 1;
73     if(a<b) swap(a,b);
74     if(a-1 > a+b-2) c = 0;
75     for(int i=1;i<=a-1;i++){
76     c = (1ll*c*(a+b-1-i))%mod;
77     c = (1ll*c*fast_pow(i,mod-2))%mod;
78     }
79     if(b == 0){n++;c=1;b=2;}
80     for(int i=1;i<n;i++) res[i].push_back(i-1),res[i].push_back(1);
81     divide(1,n-1,1);
82     c = (1ll*c*res[up[1]][a+b-2])%mod;
83     printf("%d",c);
84 }
85 
86 int main(){
87     scanf("%d%d%d",&n,&a,&b);
88     work();
89     return 0;
90 }

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325066091&siteId=291194637