51nod 1799 二分答案

基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
收藏
关注
lyk最近在研究二分答案类的问题。
对于一个有n个互不相同的数且从小到大的正整数数列a(其中最大值不超过n),若要找一个在a中出现过的数字m,一个正确的二分程序是这样子的:
 
1
2
3
4
5
6
l = 1 ;  r = n ;  mid = ( l + r )/ 2 ;
while  ( l <= r )
{
     if  ( a [ mid ] <= m )  l = mid +1 ;  else  r = mid -1 ;
     mid = ( l + r )/ 2 ;
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

最终a[r]一定等于m。
但是这个和谐的程序被熊孩子打乱了。
熊孩子在一开始就将a数组打乱顺序。(共有n!种可能)
lyk想知道最终r=k的期望。
由于小数点非常麻烦,所以你只需输出将答案乘以n!后对1000000007取模就可以了。

在样例中,共有2个数,被熊孩子打乱后的数列共有两种可能(1,2)或者(2,1),其中(1,2)经过上述操作后r=1,(2,1)经过上述操作后r=0。r=k的期望为0.5,0.5*2!=1,所以输出1。



Input


3个整数n,m,k(1<=m<=n<=10^9,0<=k<=n)。


Output


一行表示答案


Input示例


2 1 1


Output示例


1


思路:
二分范围的改变关键是mid, 假设此时mid>k,则必须存在a[mid]>m,否则必须存在a[mid]<=m。
要求r=k概率乘以n!那么就相当于求 A(m , x ) * A ( n - m  , y )*(n-x-y)! 就是排列组合问题。因为阶乘太大求不出来,所以要分段打表。
1e7--1e9每段1e7.
Code:
#include <bits/stdc++.h>
#define LL long long 
using namespace std;
const int MOD = 1e9+7;
const int AX = 1e3+66;
int P[AX] = {682498929,491101308,76479948,723816384,67347853,27368307,625544428,199888908,888050723,927880474,281863274,661224977,623534362,970055531,261384175,195888993,66404266,547665832,109838563,933245637,724691727,368925948,268838846,136026497,112390913,135498044,217544623,419363534,500780548,668123525,128487469,30977140,522049725,309058615,386027524,189239124,148528617,940567523,917084264,429277690,996164327,358655417,568392357,780072518,462639908,275105629,909210595,99199382,703397904,733333339,97830135,608823837,256141983,141827977,696628828,637939935,811575797,848924691,131772368,724464507,272814771,326159309,456152084,903466878,92255682,769795511,373745190,606241871,825871994,957939114,435887178,852304035,663307737,375297772,217598709,624148346,671734977,624500515,748510389,203191898,423951674,629786193,672850561,814362881,823845496,116667533,256473217,627655552,245795606,586445753,172114298,193781724,778983779,83868974,315103615,965785236,492741665,377329025,847549272,698611116};
const int T = 1e7;   //这里不把1e7设成常量直接用,很可能会wa
LL f( LL x ){
	int pos = x / T - 1; 
	LL ans = P[pos];
	LL lim = T * (( x / T ));
	for( LL i = x ; i > lim ; i-- ){
		ans = ( ans * i ) % MOD;
	}
	return ans ;
}

int main(){
	LL n , m , k ;
	cin >> n >> m >> k ;
	int x = 0 , y = 0; 
	LL res = 1LL;
	LL l = 1 , r = n ;
	LL mid ;
	while( l <= r ){
		mid = ( l + r ) >> 1 ;
		if( mid <= k ) { l = mid + 1; x++;}
		else { r = mid - 1 ; y ++; }
	}
	for( int i = m - x + 1 ; i <= m ; i ++ ){
		res *= i ;
		res %= MOD; 
	}
	for( int i = n - m - y + 1 ; i <= n - m ; i ++ ){
		res *= i ;
		res %= MOD; 
	}
	LL c3 ;
	if( n - x - y < 1e7 ){
		c3 = 1;
		for( int i = 2;  i <= n - x - y ; i++ ){
			c3 = c3 * i;
			c3 %= MOD;
		}
	}else{
		c3 = f( n - x - y );		
	}
	res = res * c3 % MOD;
	cout << res << endl;
	return 0;
}



猜你喜欢

转载自blog.csdn.net/frankax/article/details/79981627