牛客补题-牛客挑战赛33B题(逆元+快速幂)

鸽天的放鸽序列
在这里插入图片描述
拿到题目分析后发现是一道01序列排列组合题目。
要使权值尽可能的大,那么0只能放在奇数位置上的1后面。且第一位一定为1,不能为0。
例如

1011的权值为:1%2+1%2+2%2+3%2=3
1101的权值为:1%2+2%2+2%2+3%2=2

n-k个0,共有 \lceil k 2 \frac{k}{2} \rceil 个位置可以插空放0,故最终结果为: C n k + k 2 1 k 2 1 \LARGE C_{n-k+\lceil\frac{k}{2}\rceil-1}^ {\lceil\frac{k}{2}\rceil-1}

组合数取模用逆元+快速幂,复习一遍逆元和快速幂(阶乘打的表orz)

#include<iostream>  
#include<algorithm>  
using namespace std;  
typedef long long LL;  
#define Max  1100000  
const LL mod = 1e9 + 7;

int n,k;

LL p[Max];  
LL q[Max],ans;  
//快速幂 
LL Quick_Pow(LL base,int index){  
    LL ans=1;  
    while (index>0){  
        if (index & 1){
        	ans=(base*ans)%mod;  
		}
        base=(base*base)%mod;  
        index = index >> 1;  
    }  
    return ans;  
}  
//阶乘 
void Multy(){  
    p[0]=1;  
    q[0]=1;  
    for (int i=1;i<Max ;i++){  
        p[i]=p[i-1]*i%mod;  //N!
        q[i]=Quick_Pow(p[i],mod-2);  
    }  
}  
int main(){  
	int a,b;
    Multy();  
	cin >> n >> k;
	if( k<= 1){
		printf("1\n");
	}
	else{
		a = n - k/2- 1;
		if(k%2 == 0){
			b = k/2 - 1;
		}
		else{
			b = k/2;
		}
		ans=((p[a]*q[b]%mod)*q[a-b])%mod; // C(p,q)= n!/(q!*(p-q)!)
		printf("%lld\n",ans);  
	}
    return 0;  
}  

再放一个6ms就过了的大佬的代码

#include <bits/stdc++.h>
 
typedef long long LL;
 
const LL MOD = 1e9 + 7;
 
int n, k;
 
LL Pow(LL a, LL b) {
    LL res = 1;
    for (; b; b >>= 1) {
        if (b & 1) res = res * a % MOD;
        a = a * a % MOD;
    }
    return res;
}
 
int main() {
    scanf("%d%d", &n, &k);
    if (k <= 1) printf("1\n");
    else {
        if (k % 2 == 0) n--, k--;
        n--, k--;
        LL M = k / 2, N = n - k / 2;
        LL u = 1, d = 1;
        for (int i = 1; i <= M; i++) {
            u = u * (N - i + 1) % MOD;
            d = d * i % MOD;
        }
        printf("%lld\n", u * Pow(d, MOD - 2) % MOD);   
    }
    return 0;
}
发布了13 篇原创文章 · 获赞 1 · 访问量 454

猜你喜欢

转载自blog.csdn.net/amino_acid0617/article/details/102642381