CF960G Bandit Blues(第一类斯特林数)

传送门

可以去看看litble巨巨关于第一类斯特林数的总结

\(f(i,j)\)\(i\)个数的排列中有\(j\)个数是前缀最大数的方案数,枚举最小的数的位置,则有递推式\(f(i,j)=f(i-1,j-1)+(i-1)\times f(i-1,j)\)

这个就是第一类斯特林数

第一类斯特林数中\(S_1(n,m)\)\(\prod_{i=0}^{n-1}(x+i)\)\(x^m\)的系数,可以用分治\(FFT\)做到\(O(n\log^2n)\)的复杂度

首先\(n\)肯定是前缀最大值,所以题目要求的\(a-1\)个数一定都在\(n\)前面,\(b-1\)个数一定都在\(n\)后面。设整个序列中没有\(n\),前缀最大值的位置分别为\(p_1,p_2,...,p_k\),可以把每个\([p_i,p_{i+1}-1]\)看成一块,那么可以产生\(a+b-2\)块,然后选择其中的\(b-1\)块整个翻转然后放到\(n\)的后面,所以答案就是\[S_1(n-1,a+b-2)\times C_{a+b-2}^{b-1}\]

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=5e5+5,P=998244353,Gi=332748118;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
    R int res=1;
    for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
    return res;
}
int A[19][N],O[N],r[N];
int n,m,a,b;
void NTT(int *A,int ty,int lim){
    fp(i,0,lim-1)if(i<r[i])swap(A[i],A[r[i]]);
    for(R int mid=1;mid<lim;mid<<=1){
        R int I=(mid<<1),Wn=ksm(ty==1?3:Gi,(P-1)/I);O[0]=1;
        fp(i,1,mid-1)O[i]=mul(O[i-1],Wn);
        for(R int j=0;j<lim;j+=I)for(R int k=0;k<mid;++k){
            int x=A[j+k],y=mul(O[k],A[j+k+mid]);
            A[j+k]=add(x,y),A[j+k+mid]=dec(x,y);
        }
    }if(ty==-1)for(R int i=0,inv=ksm(lim,P-2);i<lim;++i)A[i]=mul(A[i],inv);
}
void solve(int ql,int qr,int d){
    if(ql==qr)return (void)(A[d][0]=ql,A[d][1]=1);
    int mid=(ql+qr)>>1,lim=1,l=0;
    while(lim<=qr-ql+1)lim<<=1,++l;
    solve(ql,mid,d),solve(mid+1,qr,d+1);
    fp(i,0,lim-1)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    fp(i,mid-ql+2,lim-1)A[d][i]=0;
    fp(i,qr-mid+1,lim-1)A[d+1][i]=0;
    NTT(A[d],1,lim),NTT(A[d+1],1,lim);
    fp(i,0,lim-1)A[d][i]=mul(A[d][i],A[d+1][i]);
    NTT(A[d],-1,lim);
}
int C(int n,int m){
    int k1=1,k2=1;
    fp(i,n-m+1,n)k1=mul(k1,i);
    fp(i,1,m)k2=mul(k2,i);
    return mul(k1,ksm(k2,P-2));
}
int main(){
//  freopen("testdata.in","r",stdin);
    n=read(),a=read(),b=read();
    if(!a||!b||a+b-2>n-1)return puts("0"),0;
    if(n==1)return puts("1"),0;
    solve(0,n-2,0);
    printf("%d\n",mul(A[0][a+b-2],C(a+b-2,b-1)));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/bztMinamoto/p/10210515.html