题目链接
https://codeforces.com/problemset/problem/1436/C
ps:不知道为什么vj上wa,cf上ac???
解题思路
模拟二分的过程,如果要找的pos位置大于等于mid,说明l取小了,根据题目代码, l=mid+1;;如果要找的pos位置小于mid,说明r取大,根据题目代码,r=mid;。
不同的是,我们要统计二分过程中所有mid位置上比x大的数有多少,比x小的数有多少。
为什么?
我们在乎的只是与二分有关的点,而与二分有关的点只是mid点,其他的位置的值爱是多少是多少,是多少都不影响我们二分,因为二分过渡到下一个过程的判断条件只是比较mid位置值与x的大小关系。
因此,我们假设找出mid位置上比x小的个数为le(本意为less,但是具有二义性),假设从所有比x小的个数为sumle,则我们要从sumle中选出le个数排列在比x小的mid的位置上,即A(le,sumle);
类似的,我们假设找出mid位置上比x大的个数为gr(本意为greater),假设从所有比x大的个数为sumgr,则我们要从sumgr中选出gr个数排列在比x大的mid的位置上,即A(gr,sumgr);
同时,对于吧剩下的n-sumgr-sumle个数,这其中还含有x,我们要把它排除,即还剩n-sumgr-sumle-1个数,我们要将这些数放在剩下的位置上,随便放就行,即A(n-sumgr-sumle-1,n-sumgr-sumle-1),即(n-sumgr-sumle-1)!。
这三个排列数相乘就是答案了。
AC代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1e9+7;
const int N=1e4+1000;//开大点,我怕了
int n,x,pos,le,gr;
ll fac[N];
void getfac()//求阶乘
{
fac[0]=1;
for(int i=1;i<=10100;i++)
fac[i]=fac[i-1]*i%mod;
}
ll KSM(ll x,ll p)//快速幂//不会的话代码下面有知识点补充的链接
{
ll sum=1;
while(p>0)
{
if(p&1LL) sum=sum*x%mod;
x=x*x%mod;
p>>=1;
}
return sum;
}
ll A(int x,int y)//排列数//用了个逆元//不会逆元什么的话,代码下面有知识点补充的链接
{
return fac[y]*KSM(fac[y-x],mod-2)%mod;
}
int main()
{
getfac();
cin>>n>>x>>pos;
int l=0,r=n;
while(l<r)
{
int mid=l+r>>1;
if(mid<=pos)
{
if(mid!=pos) le++;//当mid与pos位置相等的时候,说明查找到的是输入的那个,不能算比x大或者比x的小的,所以le不变,只有mid!=pos时才++
l=mid+1;//仿照题目代码写
}
else
{
gr++;
r=mid;//仿照题目代码写
}
}
cout<<A(le,x-1)*A(gr,n-x)%mod*A(n-gr-le-1,n-gr-le-1)%mod<<endl;//排列数嘛
return 0;
}
知识点的补充
总结
说实话,我真没觉得自己能AC,因为二分的边界问题太可怕了,细节太多,没想到混过去了。

京公网安备 11010502036488号