CF1717D 题解
fast_photon · · 题解
0. 前言
重在思路,不在代码。
前置知识:逆元
1. 分析
赞助商修改的
注意,打败他的人在打败他之后进行的场次赢的计入他的胜利中,就比如下图:6 号位被 5 号位打败,然后 5 号位打败 7 号位,接着 1 号位打败 5 号位,那么就是 6 号位算是赢了一场(5 打败 1)。因为如果让 6 打败 5 的话,因为预先设定的是 5 6 之间的胜者打败了 7 8 之间的胜者,所以如果能打败一个人就能抢走他这场比赛后应有的全部的胜利场次。
如果他输了
蓝色=赢,黑色=输,数字仅表示位置不表示编号
如果赞助商想让 1 号位的人赢,就需要
如果
而根据公式,
#include<iostream>
#include<cstdio>
#define maxn 100005
#define mod 1000000007
using namespace std;
long long n, k, inv[maxn], C[maxn], ans;
long long qpow(int p, int q) {
if(q == 0) return 1ll;
if(q == 1) return p;
long long kkk = qpow(p, q >> 1);
return kkk * kkk % mod * ((q & 1) ? p : 1ll) % mod;
} //就是用来计算2的幂的,也可以用每次左移1取模的方式
int main() {
scanf("%lld %lld", &n, &k);
inv[1] = 1;
for(int i = 2; i <= n; i++) {
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
}
C[n] = 1;
for(int i = n - 1; i >= 0; i--) {
C[i] = C[i + 1] * (i + 1) % mod * inv[n - i] % mod;//预处理组合数
}
for(int i = n; i > k; i--) {//这里是因为之前有过多次组合数带取模正向枚举结果k>n的然后炸飞的经历,已经养成这样的习惯了
ans += C[i];
ans %= mod;
}
cout << (qpow(2, n) - ans + mod) % mod << endl;//减完之后可能是负的,所以要加一个mod再取模
}