Codeforces Round #678 (Div. 2)C 组合数+快速幂逆元
题意:给你一个二分的模板,然后就是给你一个序列长度为N,固定序列中一个位置pos,该处的值为 x,问 我有多少种序列可以在无序的时候依旧可以使用二分找到这个x。序列是从0—N-1的。
题解:首先我们要知道,mid=L+R>>1;每次查询的这个(mid-1位置上的数)值要是在pos左边那必须是小于x,在右边一定是大于的,所以我们可以先二分pos的左右两边,找到小于等于x的个数a,大于x的个数b。注意,二分条件里面的数组是pos+1>=a[mid];因为我们查询是 从1开始,但是我们处理的a[i-1]=i;
位置从0开始但是值我们是从1开始赋,之后 我们就是一个排列了,首先是小于等于 A(x-1,a-1),去掉本身x 然后是大于的A(n-x,b)最后是剩下的数字A(n-a-b-1+1,n-a-b-1+1);然后全部乘起来
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define fio ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define mse(a,b) memset(a,b,sizeof a)
#define pb push_back
using namespace std;
const int mod=1e9+7;
const int maxx=1e7+10;
using namespace std;
const long double PI = 3.14159265358979323846;
//inline int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); } while (isdigit(ch)) { x=x*10+ch-48; ch=getchar(); } return x*f;}
// ll cc = ((1ll << 62) - 1 + (1ll << 62));
ll fa[2000];
int ans[2000];
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans%mod;
}
ll pp(ll n,ll m)
{
return fa[n]*qpow(fa[n-m]%mod,mod-2)%mod;
}
signed main()
{
fa[0]=1;
for(int i=1; i<=1000; i++)
fa[i]=fa[i-1]*i%mod,ans[i-1]=i;
int n,x,pos;
cin>>n>>x>>pos;
int l=0,r=n;
int a,b;
a=b=0;
while(l<r)
{
int mid=l+r>>1;
if(ans[mid]<=pos+1)
l=mid+1,a++;
else
r=mid,b++;
}
ll aa=a-1;
ll bb=b;
ll xx=x-1;
ll yy=n-x;
// cout<<aa<<" "<<xx<<endl;
ll sum=pp(xx,aa)%mod*pp(yy,bb)%mod*fa[n-a-b]%mod;
// cout<<fa[xx]<<endl;
// cout<<qpow(fa[xx-aa],mod-2)<<endl;
cout<<sum<<endl;
return 0;
}