模拟 排列组合

原题链接

题意简介

要求有多少种 n 的排列,能够通过二分法正确地找到放在 pos 处的数字 x。
答案对 1e9+7 取模。n<=1000。

采用的二分法如下图:

思路分析

首先,这个排列中有一个位置是固定的,就是 a[pos] = x 。

我们知道,二分查找的过程是不断缩小区间的过程,想要找到一个已经确定放在 pos 位置上的 x ,需要判断的 mid 的位置,需要的大于 x 的数的个数 c1 和小于 x 的数的个数 c0 也是固定的。

也就是说,我们只需要模拟这个二分过程,求解出 c0 和 c1,然后利用排列组合的公式去计算就行了。

\(Ans = A^{c0}_{x-1} \times A^{c1}_{n-x} \times (n-1-c0-c1)!\)

由于本题的 n 的范围较小,可以不写逆元,直接暴力求阶乘。

顺带一提,本题有一个坑点在于不一定有解。显然的,当小于 x 的数不够 c0 个或大于 x 的数不够 c1 个时无解。

代码库

#include <cstdio>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,a,b) for(int i=a;i>=b;i--)
typedef long long ll;
const int MOD=1e9+7,N=1002;
inline ll _pow(ll x,ll p){
    ll ans=1;
    while(p){
        if(p&1) ans=ans*x%MOD;
        p>>=1; x=x*x%MOD;
    }
    return ans;
}
int n,x,pos,c0,c1;
ll fact[N];
int main(){
    scanf("%d%d%d",&n,&x,&pos);
    int l=0,r=n,mid;
    while(l<r){
        mid=(l+r)>>1;
        if(mid<pos) c0++,l=mid+1;
        else if(mid==pos) l=mid+1;
        else c1++,r=mid;
    }
    fact[0]=1;
    rep(i,1,n) fact[i]=(fact[i-1]*i)%MOD;
    if(x-1-c0<0||n-x-c1<0||n-1-c0-c1<0) printf("0\n");
    else printf("%lld\n",fact[x-1]*_pow(fact[x-1-c0],MOD-2)%MOD*fact[n-x]%MOD*_pow(fact[n-x-c1],MOD-2)%MOD*fact[n-1-c0-c1]%MOD);
    return 0;
}

END

版权声明:本文为Qing-LKY原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/Qing-LKY/p/CF1436C-solution.html