Codeforces Round #678 (Div. 2) C. Binary Search组合数+快速幂逆元


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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值