CF1763D Valid Bitonic Permutations
拱形排列,指由 1 , 2 , … , n 1,2,\dots,n 1,2,…,n组成的一个排列,从数值来看,必须是先上升后下降的。
给你五个数 n , i , j , x , y n,i,j,x,y n,i,j,x,y,求有多少个排列,满足第 i i i个数为 x x x,第 j j j个数为 y y y。输出答案模 1 0 7 9 10^9_7 1079。
有多组数据。
1 ≤ n ≤ 100 1\leq n\leq 100 1≤n≤100, 1 ≤ t ≤ 100 1\leq t\leq 100 1≤t≤100
首先,我们要使 i < j , x < y i
令 k k k表示数字 n n n在序列中的位置,那么接下来,我们可以枚举 k k k。
如果 k k k在 i i i和 j j j之间,则序列大致如下
首先看第一段, y + 1 y+1 y+1到 n − 1 n-1 n−1之间的数可以放在这一段中,要放 j − k − 1 j-k-1 j−k−1个数,那么有 C n − y + 1 j − k − 1 C_{n-y+1}^{j-k-1} Cn−y+1j−k−1种放法。
然后放第二段,这里需要满足大于 y y y的数都要放在第二段,否则这就不是拱形序列。这一段必须在 n n n之前且是单调递增的一段。 [ i + 1 , j ] [i+1,j] [i+1,j]这一段放了 y y y到 n n n之间的所有数,我们还要放大于 x x x的数,那么还剩下的数字都在 x x x和 y y y之间,也就是还有 y − x − 1 y-x-1 y−x−1个数。 [ i + 1 , j ] [i+1,j] [i+1,j]这一段要放 j − i j-i j−i个数,已经放了 n − y + 1 n-y+1 n−y+1个,还要放 j − i − ( n − y + 1 ) j-i-(n-y+1) j−i−(n−y+1)个数,那么第二段的放法有 C y − x − 1 j − i − ( n − y + 1 ) C_{y-x-1}^{j-i-(n-y+1)} Cy−x−1j−i−(n−y+1)种。
对于第三段, 1 1 1到 x − 1 x-1 x−1之间的数可以放在这一段中,要放 i − 1 i-1 i−1个数,那么放法有 C x − 1 i − 1 C_{x-1}^{i-1} Cx−1i−1种。
剩下的都放第四段。
总共的放法数量为
∑ k = i + 1 j − 1 C n − y + 1 j − k − 1 × C y − x − 1 j − i − ( n − y + 1 ) × C x − 1 i − 1 \sum\limits_{k=i+1}^{j-1}C_{n-y+1}^{j-k-1}\times C_{y-x-1}^{j-i-(n-y+1)}\times C_{x-1}^{i-1} k=i+1∑j−1Cn−y+1j−k−1×Cy−x−1j−i−(n−y+1)×Cx−1i−1
如果 k k k在 j j j右边,则序列大致如下
首先看第一段,可以放 n − y − 1 n-y-1 n−y−1个数,要放 k − j − 1 k-j-1 k−j−1个数,放法有 C n − y − 1 k − j − 1 C_{n-y-1}^{k-j-1} Cn−y−1k−j−1种
然后看第二段,可以放 y − x − 1 y-x-1 y−x−1个数,要放 j − i − 1 j-i-1 j−i−1个数,放法有 C y − x − 1 j − i − 1 C_{y-x-1}^{j-i-1} Cy−x−1j−i−1种
再看第三段,可以放 x − 1 x-1 x−1个数,要放 i − 1 i-1 i−1个数,放法有 C x − 1 i − 1 C_{x-1}^{i-1} Cx−1i−1种
剩下的都放第四段。
总共的放法数量为
∑ k = j + 1 n − 1 C n − y + 1 k − j − 1 × C y − x − 1 j − i − 1 × C x − 1 i − 1 \sum\limits_{k=j+1}^{n-1}C_{n-y+1}^{k-j-1}\times C_{y-x-1}^{j-i-1}\times C_{x-1}^{i-1} k=j+1∑n−1Cn−y+1k−j−1×Cy−x−1j−i−1×Cx−1i−1
上面两个式子之和就是答案。
如果 y = = n y==n y==n,也就是说 k k k的位置已经定了,那么就不能用上面的方法来计算答案了。
如果 j = = n j==n j==n,则不可能构成拱形序列,方案数为 0 0 0。
否则在 [ i + 1 , j − 1 ] [i+1,j-1] [i+1,j−1]之间有 y − x − 1 y-x-1 y−x−1个数可以放,要放 j − i − 1 j-i-1 j−i−1个数;在 [ 1 , i − 1 ] [1,i-1] [1,i−1]之间有 x − 1 x-1 x−1个数可以放, 要放 i − 1 i-1 i−1个数。那么答案为 C y − x − 1 j − i − 1 × C x − 1 i − 1 C_{y-x-1}^{j-i-1}\times C_{x-1}^{i-1} Cy−x−1j−i−1×Cx−1i−1。
在求 C n m C_n^m Cnm时,如果 n < 0 n<0 n<0或 m < 0 m<0 m<0或 n < m n
时间复杂度为 O ( t × n ) O(t\times n) O(t×n)。
#include
using namespace std;
const int N=1000;
long long ans,jc[1005],ny[1005];
long long mod=1000000007;
long long mi(long long t,long long v){
if(!v) return 1;
long long re=mi(t,v/2);
re=re*re%mod;
if(v&1) re=re*t%mod;
return re;
}
long long C(int x,int y){
if(x<0||y<0) return 0;
if(x<y) return 0;
return jc[x]*ny[y]%mod*ny[x-y]%mod;
}
void init(){
jc[0]=1;
for(int i=1;i<=N;i++) jc[i]=jc[i-1]*i%mod;
ny[N]=mi(jc[N],mod-2);
for(int i=N-1;i>=0;i--) ny[i]=ny[i+1]*(i+1)%mod;
}
int main()
{
int T,n,i,j,x,y;
init();
scanf("%d",&T);
while(T--){
scanf("%d%d%d%d%d",&n,&i,&j,&x,&y);
if(i>j){
swap(i,j);swap(x,y);
}
if(x>y){
i=n-i+1;j=n-j+1;
swap(i,j);swap(x,y);
}
ans=0;
if(y==n){
ans=C(y-x-1,j-i-1)*C(x-1,i-1)%mod;
if(j==n) ans=0;
printf("%lld\n",ans);
continue;
}
for(int k=i+1;k<=j-1;k++){
ans=(ans+C(n-y-1,j-k-1)*C(y-x-1,j-i-(n-y+1))%mod*C(x-1,i-1)%mod)%mod;
}
for(int k=j+1;k<=n-1;k++){
ans=(ans+C(n-y-1,k-j-1)*C(y-x-1,j-i-1)%mod*C(x-1,i-1)%mod)%mod;
}
printf("%lld\n",ans);
}
return 0;
}