鸽天的放鸽序列
拿到题目分析后发现是一道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,共有 个位置可以插空放0,故最终结果为:
组合数取模用逆元+快速幂,复习一遍逆元和快速幂(阶乘打的表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;
}