Codeforces 960G. Bandit Blues
Description
你需要构造一个长度为 \(n\) 的排列 , 使得一个数作为前缀最大值的次数为 \(A\) , 作为后缀最大值的次数为 \(B\) , 求满足要求的排列个数 .
题面
Solution
同 \(FJOI\) 建筑师 .
从 \(n\) 到 \(1\) 依次加入 , 对于 \(n\) ,对 \(A,B\) 的出现次数都会贡献 \(1\) .
剩下的数 , 如果放在左边则对 \(A\) 有贡献 , 放在右边则对 \(B\) 有贡献 , 放在中间则没有贡献 .
我们从组合意义上分析 , 那么相当于是操作 \(n-1\) 轮 , 每轮可以选择 从 \((0,0)\) 向走 \((A-1,B-1)\) 一步或者停顿的方案数 .
从 \((0,0)\) 走向 \((A-1,B-1)\) 的不同方案数为 \(C(A+B-2,A-1)\)
并且还要求出分配停顿的位置(确定每个位置停了几次)的不同方案数 .
这个可以 \(DP\) 设前 \(i\) 次操作 , 走了 \(j\) 步的方案数, \(f[i][j]=f[i-1][j-1]+f[i-1][j]*(i-1)\) , 这个东西就等于第一类斯特林数 .
由于\(S(n,m)\)等于 \(P(x,n)\) 的第 \(x^m\) 项系数 , 就可以对应一个上升幂的 \(x^m\) 项系数.
可以分治+\(NTT\) 合并出一个长度为 \(n\) 的多项式 , 就可以求出第一类斯特林数的某一行了 .
#include<bits/stdc++.h>
using namespace std;
template<class T>void gi(T &x){
int f;char c;
for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
}
const int N=4e5+10,mod=998244353;
inline int qm(int x,int k){
int sum=1;
for(;k;k>>=1,x=1ll*x*x%mod)if(k&1)sum=1ll*sum*x%mod;
return sum;
}
int n,a[20][N],R[N],L=0;
inline int C(int n,int m){
if(n<m || n<0 || m<0)return 0;
int ret=1,I=1;
for(int i=1;i<=m;i++)ret=1ll*ret*(n-i+1)%mod,I=1ll*I*i%mod;
return 1ll*ret*qm(I,mod-2)%mod;
}
inline void NTT(int *A){
for(int i=0;i<n;i++)if(i<R[i])swap(A[i],A[R[i]]);
for(int i=1;i<n;i<<=1){
int t0=qm(3,(mod-1)/(i<<1)),x,y;
for(int j=0;j<n;j+=i<<1){
int t=1;
for(int k=0;k<i;k++,t=1ll*t*t0%mod){
x=A[j+k];y=1ll*A[j+k+i]*t%mod;
A[j+k]=(x+y)%mod;A[j+k+i]=(x-y+mod)%mod;
}
}
}
}
inline void mul(int *A,int *B){
NTT(A);NTT(B);
for(int i=0;i<n;i++)A[i]=1ll*A[i]*B[i]%mod;
NTT(A);reverse(A+1,A+n);
for(int i=0,t=qm(n,mod-2);i<n;i++)A[i]=1ll*A[i]*t%mod;
}
inline void solve(int l,int r,int d){
if(l==r){a[d][0]=l;a[d][1]=1;return ;}
int mid=(l+r)>>1,m=r-l+1;
solve(l,mid,d+1);
for(int i=0;i<=m;i++)a[d][i]=a[d+1][i];
solve(mid+1,r,d+1);
for(n=1,L=0;n<=m;n<<=1)L++;
for(int i=mid-l+2;i<n;i++)a[d][i]=0;
for(int i=r-mid+1;i<n;i++)a[d+1][i]=0;
for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
mul(a[d],a[d+1]);
}
int A,B;
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
cin>>n>>A>>B;
if(n==1){
if(A+B-2>=0)puts("1");else puts("0");
exit(0);
}
solve(0,n-2,0);
cout<<1ll*a[0][A+B-2]*C(A+B-2,A-1)%mod;
return 0;
}