CF1763D Valid Bitonic Permutations

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 1n100 1 ≤ t ≤ 100 1\leq t\leq 100 1t100


题解

首先,我们要使 i < j , x < y ii<j,x<y。方法如下:

  • 如果 i > j i>j i>j,则交换 i , j i,j i,j,交换 x , y x,y x,y
  • 上面的操作进行后,如果 x > y x>y x>y,则 i = n − i + 1 i=n-i+1 i=ni+1 j = n − j + 1 j=n-j+1 j=nj+1,再交换 i , j i,j i,j,交换 x , y x,y x,y,相当于将序列前后翻转,这样求出的答案与原来的是等价的

k k k表示数字 n n n在序列中的位置,那么接下来,我们可以枚举 k k k

第一种情况: k k k i i i j j j中间

如果 k k k i i i j j j之间,则序列大致如下

CF1763D Valid Bitonic Permutations_第1张图片

首先看第一段, y + 1 y+1 y+1 n − 1 n-1 n1之间的数可以放在这一段中,要放 j − k − 1 j-k-1 jk1个数,那么有 C n − y + 1 j − k − 1 C_{n-y+1}^{j-k-1} Cny+1jk1种放法。

然后放第二段,这里需要满足大于 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 yx1个数。 [ i + 1 , j ] [i+1,j] [i+1,j]这一段要放 j − i j-i ji个数,已经放了 n − y + 1 n-y+1 ny+1个,还要放 j − i − ( n − y + 1 ) j-i-(n-y+1) ji(ny+1)个数,那么第二段的放法有 C y − x − 1 j − i − ( n − y + 1 ) C_{y-x-1}^{j-i-(n-y+1)} Cyx1ji(ny+1)种。

对于第三段, 1 1 1 x − 1 x-1 x1之间的数可以放在这一段中,要放 i − 1 i-1 i1个数,那么放法有 C x − 1 i − 1 C_{x-1}^{i-1} Cx1i1种。

剩下的都放第四段。

总共的放法数量为

∑ 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+1j1Cny+1jk1×Cyx1ji(ny+1)×Cx1i1


第二种情况: k k k j j j右边

如果 k k k j j j右边,则序列大致如下

CF1763D Valid Bitonic Permutations_第2张图片

首先看第一段,可以放 n − y − 1 n-y-1 ny1个数,要放 k − j − 1 k-j-1 kj1个数,放法有 C n − y − 1 k − j − 1 C_{n-y-1}^{k-j-1} Cny1kj1

然后看第二段,可以放 y − x − 1 y-x-1 yx1个数,要放 j − i − 1 j-i-1 ji1个数,放法有 C y − x − 1 j − i − 1 C_{y-x-1}^{j-i-1} Cyx1ji1

再看第三段,可以放 x − 1 x-1 x1个数,要放 i − 1 i-1 i1个数,放法有 C x − 1 i − 1 C_{x-1}^{i-1} Cx1i1

剩下的都放第四段。

总共的放法数量为

∑ 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+1n1Cny+1kj1×Cyx1ji1×Cx1i1

上面两个式子之和就是答案。


一些特判

如果 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,j1]之间有 y − x − 1 y-x-1 yx1个数可以放,要放 j − i − 1 j-i-1 ji1个数;在 [ 1 , i − 1 ] [1,i-1] [1,i1]之间有 x − 1 x-1 x1个数可以放, 要放 i − 1 i-1 i1个数。那么答案为 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} Cyx1ji1×Cx1i1

在求 C n m C_n^m Cnm时,如果 n < 0 n<0 n<0 m < 0 m<0 m<0 n < m nn<m,则返回 0 0 0

时间复杂度为 O ( t × n ) O(t\times n) O(t×n)

code

#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;
}

你可能感兴趣的:(题解,c++,题解)