洛谷 P3726 抛硬币 (拓展卢卡斯+数论)
https://www.luogu.org/problemnew/show/P3726
题意:
思路:
我们可以把A和B的硬币种类看成一个01串
比如:就代表A的1,2硬币是反面,而3硬币是正面,而B硬币的1,2是反面
我们设A硬币正面朝上的个数为,B硬币正面朝上的为
因为 所以我们现在可以把它分为两种情况:
应为所以当时,我们把01串反转一下,就变成这样A就输了
所以A赢得情况反转一下,A就输了
那么我们可以得知:总情况=A获胜+B获胜+平局
所以
范德蒙恒等式
继续:
与a==b的情况类似,我们考虑的情况,这时所以,当B获胜的情况反转一下,A就能获胜
而当有的时,反转A不一定会输,即当时,A仍然会获胜
类似这种情况
而特殊情况:
根据前面的范德蒙恒等式
所以当结果为
这里我们遇见了一个求和除以2,因为当时当时,,因为
所以这个组合数位于杨辉三角的两侧,我们可以只计算一侧的值就等于除以2了
但是当多出来一个,根据前面的可以化简为
最后
结束
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int Mod = 999911659;
const int maxn = 2e6 + 5;
const double eps = 0.00000001;
const int INF = 2147483647;
LL Pre[2][maxn];
LL d1, d2;
LL a, b, k;
LL extend_gcd(LL a, LL b, LL &x, LL &y) {
if(!b) {
x = 1; y = 0;
return a;
}
LL d = extend_gcd(b, a % b, x, y);
LL t = x;
x = y; y = t - (a / b) * y;
return d;
}
LL mul(LL a, LL b, LL P){
LL L = a * (b >> 25LL) % P * (1LL << 25) % P;
LL R = a * (b & ((1LL << 25) - 1)) % P;
return (L + R) % P;
}
LL Pow(LL a, LL b, LL P) {
LL ans = 1; a %= P;
while(b) {
if(b & 1) ans = mul(ans, a, P);
a = mul(a, a, P);
b >>= 1;
}
return ans;
}
LL getInv(LL a, LL p) {
LL x, y;
extend_gcd(a, p, x, y);
x = (x % p + p) % p;
return x;
}
LL CRT(LL m, LL p, LL P) {
return mul(mul(m, (P / p), P), getInv(P / p, p), P);
}
LL Mul(LL n, LL pi, LL pk) {
if(n <= 1) return 1;
LL ans = Pow(Pre[pi != 2][pk], n / pk, pk);
if(n % pk) ans = mul(ans, Pre[pi != 2][n % pk], pk);
return mul(ans, Mul(n / pi, pi, pk), pk);
}
LL C(LL n, LL m, LL pi, LL pk) {
if(n < m) return 0;
LL r = 0;
for(LL i = n; i; i /= pi) r += i / pi;
for(LL i = m; i; i /= pi) r -= i / pi;
for(LL i = n - m; i; i /= pi) r -= i / pi;
if(r >= k) return 0;
LL a = Mul(n, pi, pk);
LL b = getInv(Mul(m, pi, pk), pk);
LL c = getInv(Mul(n - m, pi, pk), pk);
LL ans = mul(mul(a, b, pk), c, pk);
return mul(ans, Pow(pi, r, pk), pk);
}
LL ex_lucas(LL n, LL m, LL P) {
LL ans = 0;
ans = (ans + CRT(C(n, m, 2, d1), d1, P)) % P;
ans = (ans + CRT(C(n, m, 5, d2), d2, P)) % P;
return ans;
}
void init(LL pi, LL pk) {
Pre[pi != 2][0] = 1;
for (int i = 1; i <= pk; i ++) {
Pre[pi != 2][i] = Pre[pi != 2][i - 1];
if(i % pi) Pre[pi != 2][i] = mul(Pre[pi != 2][i], i, pk);
}
}
LL solve(LL a, LL b, LL P) {
LL ans = Pow(2, a + b - 1, P);
if(a == b) ans = (ans - ex_lucas(2 * a - 1, a, P) + P) % P;
else {
for (int i = 1; i <= (a - b - 1) / 2; i ++)
ans = (ans + ex_lucas(a + b, b + i, P)) % P;
if(!((a + b) & 1)) ans = (ans + ex_lucas(a + b - 1, (a + b) / 2, P)) % P;
}
return ans;
}
int main()
{
init(2, 512); init(5, 1953125);
while(~scanf("%lld %lld %lld", &a, &b, &k)) {
d1 = Pow(2, k, INF); d2 = Pow(5, k, INF);
LL P = Pow(10, k, INF);
LL t = solve(a, b, P);
while(t < P / 10) {
printf("0");
P /= 10;
}
printf("%lld\n", t);
}
return 0;
}