题目描述
You are given five integers n n n , i i i , j j j , x x x , and y y y . Find the number of bitonic permutations B B B , of the numbers 1 1 1 to n n n , such that B i = x B_i=x Bi=x , and B j = y B_j=y Bj=y . Since the answer can be large, compute it modulo 1 0 9 + 7 10^9+7 109+7 .
A bitonic permutation is a permutation of numbers, such that the elements of the permutation first increase till a certain index k k k , 2 ≤ k ≤ n − 1 2 \le k \le n-1 2≤k≤n−1 , and then decrease till the end. Refer to notes for further clarification.
题意简述
有五个整数 n , l , r , x , y n,l,r,x,y n,l,r,x,y 和一个长度为 n n n 的排列 a a a,其中 a l = x , a r = y a_l=x,a_r=y al=x,ar=y。求有多少个排列满足先升后降。
题解
首先对 x , y x,y x,y 进行处理,若 x > y x>y x>y,则把整个排列翻转,这样, x x x 小于 y y y 方便后面计算。当然, l , r l,r l,r 也要跟着翻转分别变为 n − l + 1 , n − r + 1 n-l+1,n-r+1 n−l+1,n−r+1。
枚举最高点 n n n 在位置 i i i,此时分三种情况考虑:
-
i
i
i 在区间
(
l
,
r
)
(l,r)
(l,r) 内,这里放个图方便理解
方便起见,首先考区间 ( i , r ) (i,r) (i,r) 内的方案,区间内有 n − y − 1 n-y-1 n−y−1 个数可以选,有 r − i − 1 r-i-1 r−i−1 个位置可以放,方案数为 ( n − y − 1 r − i − 1 ) \dbinom{n-y-1}{r-i-1} (r−i−1n−y−1)
接着考虑区间 ( l , i ) (l,i) (l,i) 内的方案,这时就有些复杂了。由于前面 n − y − 1 n-y-1 n−y−1 个数并没有完全选完,而没选完的这些数只能放在区间 ( l , i ) (l,i) (l,i) 内,它们在区间 ( l , i ) (l,i) (l,i) 内已经占了位置,所以区间 ( l , i ) (l,i) (l,i) 内有 i − l − 1 − ( n − y − 1 − ( r − i − 1 ) ) i-l-1-\left(n-y-1-\left(r-i-1\right)\right) i−l−1−(n−y−1−(r−i−1)) 个位置可以放数;有哪些数可以选呢?只能选 x x x 到 y y y 之间的数,因为 y y y 到 n n n 之间的数已经放好了。方案数即为 ( y − x − 1 i − l − 1 − ( n − y − 1 − ( r − i − 1 ) ) ) \dbinom{y-x-1}{i-l-1-\left(n-y-1-\left(r-i-1\right)\right)} (i−l−1−(n−y−1−(r−i−1))y−x−1)
还要考虑区间 [ 1 , l ) [1,l) [1,l) 的情况,方案数就是 ( x − 1 l − 1 ) \dbinom{x-1}{l-1} (l−1x−1)
至于区间 ( y , n ] (y,n] (y,n] 就选剩下的,方案数就是 1 1 1
把方案乘起来即为对答案的贡献。 -
i
i
i 在区间
(
r
,
n
)
(r,n)
(r,n) 内,如图
这个情况就比较简单,区间 ( r , i ) (r,i) (r,i) 的方案数为 ( n − y − 1 i − r − 1 ) \dbinom{n-y-1}{i-r-1} (i−r−1n−y−1),区间 ( l , r ) (l,r) (l,r) 的方案数为 ( y − x − 1 r − l − 1 ) \dbinom{y-x-1}{r-l-1} (r−l−1y−x−1),区间 [ 1 , l ) [1,l) [1,l) 的方案数为 ( x − 1 l − 1 ) \dbinom{x-1}{l-1} (l−1x−1),区间 ( i , n ] (i,n] (i,n] 选剩下的。
把方案乘起来即为对答案的贡献。 - 还有一种情况要特判:
y
=
n
y=n
y=n,这种情况要特判,不用枚举最高点。
这种情况也比较简单,区间 ( l , i ) (l,i) (l,i) 的方案数为 ( n − x − 1 r − l − 1 ) \dbinom{n-x-1}{r-l-1} (r−l−1n−x−1),区间 [ 1 , l ) [1,l) [1,l) 的方案数为 ( x − 1 l − 1 ) \dbinom{x-1}{l-1} (l−1x−1),区间 ( r , n ] (r,n] (r,n] 选剩下的。
对答案的贡献为二者乘积。
这里还有个点很坑,如果 r = n r=n r=n 就不可能出现排列先升后降的情况,应该输出 0 0 0。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int n,l,r,x,y;
ll f[1001],inv[1001];
ll ksm(ll a,ll b)
{
ll ans=1;
while(b){
if(b&1) ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
ll c(int n,int m)
{
if(n<m||n<0||m<0) return 0;
return f[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
f[0]=1;
for(int i=1;i<=1000;i++) f[i]=f[i-1]*i%mod;
inv[1000]=ksm(f[1000],mod-2);
for(int i=999;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
int t;
cin>>t;
while(t--){
cin>>n>>l>>r>>x>>y;
if(x>y) l=n-l+1,r=n-r+1,swap(x,y),swap(l,r);
if(y==n){
if(r==n) puts("0");
else cout<<c(n-x-1,r-l-1)*c(x-1,l-1)%mod<<endl;
continue;
}
ll ans=0;
for(int i=l+1;i<r;i++){
ans=(ans+c(n-y-1,r-i-1)*c(y-x-1,r-l+y-1-n)%mod*c(x-1,l-1))%mod;
}
for(int i=r+1;i<n;i++){
ans=(ans+c(n-y-1,i-r-1)*c(y-x-1,r-l-1)%mod*c(x-1,l-1))%mod;
}
cout<<ans<<endl;
}
}