lyk最近在研究二分答案类的问题。
对于一个有n个互不相同的数且从小到大的正整数数列a(其中最大值不超过n),若要找一个在a中出现过的数字m,一个正确的二分程序是这样子的:
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;
}