51nod1799-二分答案

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;

}

最终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

alpq654321 (题目提供者)

这道题目等价于问你有多少种排列方案,使得对这个序列做一遍关键字为m的二分查找会停在k位置。

如果当前k>mid,则要停在k位置的话,m必须>a[mid],反之亦然,这使我们知道了关于a[i]和m的大小关系的logn个条件,然后就要计算方案数了,对于有限制的数,直接暴力算好了,剩下的方案数就是一个阶乘了,求阶乘的时候打表+分块就可以水过了

这里的表表示每10000000个的阶乘值。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define pp 1000000007

ll n;
const ll cnt[] =
{1, 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};
ll calc(ll x)
{
    ll uu=cnt[x/10000000];
    for(ll i=x/10000000*10000000+1;i<=x;i++)
    uu=uu*i%pp;
    return uu;
}
int main()
{
    ll m,k,tot=1,less_num=0,bigger_num=0;
    scanf("%lld %lld %lld",&n,&m,&k);
    ll l=1,r=n;
    while(l<=r)
    {
        ll mid=(l+r)>>1;
        if(mid<=k) less_num++,l=mid+1;else bigger_num++,r=mid-1;
    }
    //tot=A(m,less_num)*A((n-m+1),bigger_num);
    //tot*=(n-less_num-bigger_num)!;
     for(ll i=1;i<=less_num;i++)
         tot=(m-i+1)*tot%pp;
    for(ll i=1;i<=bigger_num;i++)
        tot=(n-m+1-i)*tot%pp;
    cout<<tot*calc(n-less_num-bigger_num)%pp<<endl;
 } 
时间: 2024-10-03 02:28:15

51nod1799-二分答案的相关文章

Codeforces 772A Voltage Keepsake - 二分答案

You have n devices that you want to use simultaneously. The i-th device uses ai units of power per second. This usage is continuous. That is, in λ seconds, the device will use λ·ai units of power. The i-th device currently has bi units of power store

HDU3081Marriage Match II(二分答案+并查集+最大流SAP)经典

Marriage Match II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2507    Accepted Submission(s): 856 Problem Description Presumably, you all have known the question of stable marriage match. A

Codeforce 371C Hamburgers (二分答案)

题目链接 Hamburgers 二分答案,贪心判断即可. 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define REP(i,n) for(int i(0); i < (n); ++i) 6 #define LL long long 7 8 char str[1010]; 9 LL len; 10 LL b, c, s, nb, nc, ns, pb, pc, ps; 11 LL money; 12 13 bool

POJ 3080 Blue Jeans(后缀数组+二分答案)

[题目链接] http://poj.org/problem?id=3080 [题目大意] 求k个串的最长公共子串,如果存在多个则输出字典序最小,如果长度小于3则判断查找失败. [题解] 将所有字符串通过拼接符拼成一个串,做一遍后缀数组,二分答案,对于二分所得值,将h数组大于这个值的相邻元素分为一组,判断组内元素是否覆盖全字典,是则答案成立,对于答案扫描sa,输出第一个扫描到的子串即可. [代码] #include <cstdio> #include <cstring> #inclu

【二分答案+智障的字符串hash】BZOJ2946-[Poi2000]公共串(Ranklist倒一达成!!!!!)【含hash知识点】

[题目大意] 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. [字符串hash的小笔记] hash[i]=(hash[i-1]*p+idx(s[i]))%mod,idx为映射值,一般a..z映射1..26: 习惯上,p取一个6到8位的素数即可,mod一般取大素数 1e9+7(1000000007)或1e9+9(1000000009). hash[i]=(hash[i-1]*p+idx(s[i]))%mod 表示第 i 个前缀的hash值,是一个hash的前缀和,那么,要求S[l…r]

IndiaHacks 2016 - Online Edition (Div. 1 + Div. 2) 二分答案 + 网络流

这道题的意思是给你一个有向图, 每条边上有一个最大载重量, 现在有x头牛要从顶点1走向顶点n, 每头牛要载的重量都是一样的, 问你最多能载多少的重量? 可以二分答案, 算出每头牛的载重, 然后修改边权, 跑一次最大流即可判断当前答案是否正确, 二分答案即可, 注意由于原始边权/每头牛的载重量可能会很大, 因此我们在修改边权时应该注意这一点,将边权的最大值控制在1000000之内, 防止溢出, 代码如下: #include <bits/stdc++.h> using namespace std;

BZOJ 1305 CQOI2009 dance跳舞 二分答案+最大流

题目大意:给定n个男生和n个女生,一些互相喜欢而一些不.举行几次舞会,每次舞会要配成n对.不能有同样的组合出现.每一个人仅仅能与不喜欢的人跳k次舞,求最多举行几次舞会 将一个人拆成两个点.点1向点2连一条流量为k的边.两个人若互相喜欢则点1之间连边,不喜欢则点2之间连边 对于每个要验证的x值 将每个人的点1向源或汇连一条流量为x的边 然后二分答案跑最大流就可以 #include<cstdio> #include<cstring> #include<iostream> #

Educational Codeforces Round 3:D. Gadgets for dollars and pounds(二分答案+贪心)

看了菊苣的理解才知道怎么写..根本没思路啊一开始... 天数肯定在1~n之间,二分答案. 可以用保存前i天的最低美元和英镑汇率,没有规定哪天买,每天也没有购买数量限制,所以二分出一个答案mid的后,就在前mid天中汇率最低的时候一次性购入最便宜的就行了,judge一下总花费 打印答案的时候以ans为结果,再模拟一遍就好 #include"cstdio" #include"queue" #include"cmath" #include"s

BZOJ 1189: [HNOI2007]紧急疏散evacuate( BFS + 二分答案 + 匈牙利 )

我们可以BFS出每个出口到每个人的最短距离, 然后二分答案, 假设当前答案为m, 把一个出口拆成m个表示m个时间, 点u到出口v的距离为d, 那么u->v的[d, m]所有点连边, 然后跑匈牙利去check就行了...其实这道题挺好想但是码量还是挺大的.... ----------------------------------------------------------------------------- #include<cstdio> #include<cstring&

BZOJ 1816: [Cqoi2010]扑克牌( 二分答案 )

二分答案.. 一开始二分的初始右边界太小了然后WA,最后一气之下把它改成了INF... ------------------------------------------------------------------------ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define rep( i , n ) for( int i = 0 ; i