题目链接
题目翻译:
Andrey认为自己是一个成功的开发者,但事实上他直到最近才知道二分搜索算法。在阅读一些文献之后,Andrey知道了这个算法是为了在一个数列中快速地找到某个确定的值x。对于下标从0开始的数组a和整数x,下面是算法的伪代码:
注意数组中数字的下标从0开始,整数相除结果向下取整。
Andrey发现只有当数组是有序的,算法才起作用。然而,他发现这个说法是不正确的,因为有些乱序的数组,也能通过二分搜索算法找到数字x!
Andrey想要给书的作者写一封信,但是在此之前他必须先找到一个长度为n,且能够通过二分搜索算法找到x的permutations数组。permutation数组指的是由n个不同的,介于1到n之间的数字组成,以任意顺序排列的数组。
帮助Andrey找到满足上述条件的permutation数组的个数,其中要求x位于下标为pos,且二分搜索算法能找到x(return true)。因为结果可能会非常大,输出对109+7取余的结果。
解题思路:
首先我们要计算出大于x的数的个数和小于x的数的个数,分别是n-x,x-1,分别存入变量maxnum和minnum中,变量ans保存最终的结果,初始值为1。然后模拟二分搜索算法的过程,当middle>pos,表示下标为middle的数字必须大于x,这样才有可能找到x,共有maxnum种可能。同理当middle<pos的时候,表示下标为middle的数字必须小于x,共有minnum种可能。所以每轮我们只需要将可能数乘以ans就可以了(ans=(maxnum或minnum)×ans%(109+7)),而且每轮结束我们要更新maxnum和minnum的值,maxnum- -或minnum- -。在最后,因为还有几个位置上的数字没确定,所以要把剩下的数字(maxnum+minnum)可能的组合数也算在内。
有人可能会问,如果maxnum或minnum小于等于0了怎么办?maxnum或minnum的值小于等于0,说明不存在这样数组,结果就是0。
还有一个问题就是,找到x之后是不是直接停止循环?我就犯了这个错误,题目没有说找到x后就停止循环,所以我们应该根据图片里的伪代码,继续执行下去。
代码:
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<cstdio>
#include<cmath>
#define inf 0x3f3f3f3f
using namespace std;
const int MOD = 1000000007;
int main(){
// freopen("1.txt","r",stdin);
int n,x,pos,maxnum,minnum,left,right,middle;
long long ans=1;
cin>>n>>x>>pos;
maxnum=n-x,minnum=x-1;
left=0,right=n;
while(left<right){
middle=(left+right)/2;
if(middle<pos){
ans=ans*minnum%MOD;
minnum--;
left=middle+1;
}else if(middle>pos){
ans=ans*maxnum%MOD;
maxnum--;
right=middle;
}else{
left=middle+1;
}
}
for(int i=1;i<=maxnum+minnum;i++){
ans=ans*i%MOD;
}
cout<<ans<<endl;
return 0;
}
总结:
在比赛结束前AC了,结果第二天一觉醒来变WA了…
男儿有泪不轻弹。
看题还需细心。
最后献上大佬的操作
我要坚强!