我们考虑将已经维护好了\(2∽n\)的数列现在考虑插入最小值
然后现在插入最小值\(1\)
现在我们使用\(dp(i,j)\)表示前\(i\)个数一共存在\(j\)个前缀最大值的方案数
我们如果放在开头 那么贡献就是\(dp(i-1,j-1)\)
如果放在别的位置就是\(dp(i-1,j)\)
所以
\[dp(i,j)=dp(i-1,j-1)+(i-1)* dp(i-1,j)\]
等一下 这就是第一类\(Strling\)数
\[S(n,m)=S(n-1,m-1)+(n-1)* S(n-1,m)\]
然后我们考虑怎么计算题目要求的
首先我们考虑对于一个序列\(i\)存在\(j\)个前缀最小大值
翻转之后就是存在\(j\)个后缀最大值
所以我们考虑当前最大值\(n\)插入的位置
那么一定是左边存在\(a-1\)个前缀最大值 右边存在\(b-1\)个后缀最大值
那么答案就是
\[ans=\sum_{i=a-1}^{n-b}dp(i,a-1)* dp(n-i-1,b-1)* C_{n-1}^i\]
但是我们无须枚举
考虑当前是\(dp(n-1,a+b-2)\)
我们将最大值\(n\)插入第\(a-1\)个之后
然后剩余的\(b-1\)到后面然后翻转 就成了我们要的序列
所以就是
\[ans=dp(n-1,a+b-2)* C_{a+b-2}^{a-1}\]
\[x(x+1)(x+2)......(x+n-1)=\sum_{i=0}^nS(n,i)x^i\]
所以我们可以使用分治\(NTT\)求
/*-------------OI使我快乐-------------*/
int n,cdy,wzy;
ll ans[20][N],key[N];
IL ll qpow(ll x,ll y)
{ll res=1;for(;y;y>>=1,x=x*x%mod) if(y&1) res=res*x%mod;return res;}
IL ll C(ll x,ll y)
{
ll res1=1,res2=1;
for(R ll i=x-y+1;i<=x;++i) res1=res1*i%mod;
for(R ll i=1;i<=y;++i) res2=res2*i%mod;
return res1*qpow(res2,mod-2)%mod;
}
IL void NTT(ll *A,int lim,int knd)
{
for(R int i=0;i<lim;++i) if(i<key[i]) swap(A[i],A[key[i]]);
for(R int mid=1;mid<lim;mid<<=1)
{
ll Wn=qpow(knd==1 ? 3:Gi,(mod-1)/(mid<<1));
for(R int j=0;j<lim;j+=(mid<<1))
{
ll w=1;
for(R int k=0;k<mid;++k,w=w*Wn%mod)
{
ll x=A[j+k],y=w*A[j+k+mid]%mod;
A[j+k]=(x+y)%mod;A[j+k+mid]=(x-y+mod)%mod;
}
}
}
if(knd==-1)
{
ll inv=qpow(lim,mod-2);
for(R int i=0;i<lim;++i) A[i]=A[i]*inv%mod;
return;
}
}
IL void solve(int si,int le,int ri)
{
if(le==ri) {ans[si][0]=le;ans[si][1]=1;return;}
int mid=(le+ri)>>1;
solve(si+1,le,mid);
for(R int i=0;i<=mid-le+1;++i) ans[si][i]=ans[si+1][i];
solve(si+1,mid+1,ri);
int all=0,lim=0;
for(lim=1;lim<=(ri-le+1)+2;lim<<=1) ++all;
for(R int i=0;i<lim;++i) key[i]=((key[i>>1]>>1)|((i&1)<<(all-1)));
for(R int i=mid-le+2;i<lim;++i) ans[si][i]=0;
for(R int i=ri-mid+1;i<lim;++i) ans[si+1][i]=0;
NTT(ans[si],lim,1);NTT(ans[si+1],lim,1);
for(R int i=0;i<lim;++i) ans[si][i]=ans[si][i]*ans[si+1][i]%mod;
NTT(ans[si],lim,-1);
}
int main()
{
// freopen("lzxkj.in","r",stdin);
// freopen("lzxkj.out","w",stdout);
read(n);read(cdy);read(wzy);
if(!cdy||!wzy||cdy+wzy-1>n) {puts("0");return 0;}
if(n==1) {puts("1");return 0;}
solve(0,0,n-2);
printf("%lld\n",ans[0][cdy+wzy-2]*C(cdy+wzy-2,cdy-1)%mod);
// fclose(stdin);
// fclose(stdout);
return 0;
}
原文:https://www.cnblogs.com/LovToLZX/p/10590502.html