[HNOI 2017]抛硬币

Description

题库链接

两人抛硬币一人 (a) 次,一人 (b) 次。记正面朝上多的为胜。问抛出 (a) 次的人胜出的方案数。

(1le a,ble 10^{15},ble ale b+10000,1le kle 9)

Solution

比较难,不会写,代码都是抄题解的...题解链接

Code

//It is made by Awson on 2018.3.6
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const LL INF = ~0u>>1;
const LL mod5 = 1953125, mod2 = 512;

LL a, b, k, mi2, mi5, yzh, K;
LL f[6][mod5+1];

void print(LL x, LL rest) {if (rest == 0) return; print(x/10, rest-1); putchar(x%10+'0'); }
LL quick_pow(LL a, LL b, LL p) {
  LL ans = 1;
  while (b) {
    if (b&1) ans = ans*a%p;
    b >>= 1, a = a*a%p;
  }
  return ans;
}
void ex_gcd(LL a, LL b, LL &x, LL &y) {
  if (b == 0) {x = 1, y = 0; return; }
  ex_gcd(b, a%b, x, y);
  LL t = x; x = y; y = t-a/b*y;
}
LL inv(LL a, LL b) {
  LL x, y; ex_gcd(a, b, x, y);
  return (x%b+b)%b;
}
LL mul(LL n, LL pi, LL pk) {
  if (n == 0) return 1;
  LL ans = f[pi][pk]%pk;
  ans = quick_pow(ans, n/pk, pk);
  ans = ans*f[pi][n%pk]%pk;
  return ans*mul(n/pi, pi, pk)%pk;
}
LL C(LL n, LL m, LL pi, LL pk, bool flag) {
  LL k = 0;
  for (LL i = n; i; i = i/pi) k += i/pi;
  for (LL i = m; i; i = i/pi) k -= i/pi;
  for (LL i = n-m; i; i = i/pi) k-= i/pi;
  if (pi == 2 && !flag) --k; if (k >= K) return 0;
  LL a = mul(n, pi, pk), b = mul(m, pi, pk), c = mul(n-m, pi, pk);
  LL ans = a*inv(b, pk)%pk*inv(c, pk)%pk*quick_pow(pi, k, pk)%pk;
  if (pi == 5 && !flag) ans = ans*inv(2, pk)%pk;
  return ans;
}
LL ex_lucas(LL n, LL m, bool flag) {return (C(n, m, 2, mi2, flag)*mi5%yzh*inv(mi5, mi2)%yzh+C(n, m, 5, mi5, flag)*mi2%yzh*inv(mi2, mi5)%yzh+yzh)%yzh; }
void work() {
  K = k; mi2 = quick_pow(2, k, INF), mi5 = quick_pow(5, k, INF), yzh = mi2*mi5;
  if (a == b) print((quick_pow(2, a*2-1, yzh)-ex_lucas(a*2, a, 0)+yzh)%yzh, k), puts("");
  else {
    LL ans = quick_pow(2, a+b-1, yzh);
    for (LL i = (a+b)/2+1; i < a; i++) ans = (ans+ex_lucas(a+b, i, 1))%yzh;
    if ((a+b)%2 == 0) ans = (ans+ex_lucas(a+b, (a+b)/2, 0))%yzh;
    print(ans, k), puts("");
  }
}
int main() {
  f[2][0] = f[5][0] = f[2][1] = f[5][1] = 1;
  for (LL i = 2; i <= mod2; i++) f[2][i] = (f[2][i-1])*(i%2 == 0 ? 1 : i)%mod2;
  for (LL i = 2; i <= mod5; i++) f[5][i] = (f[5][i-1])*(i%5 == 0 ? 1 : i)%mod5;
  while (~scanf("%lld%lld%lld", &a, &b, &k)) work(); return 0;
}
原文地址:https://www.cnblogs.com/NaVi-Awson/p/8516667.html