[AH2017/HNOI2017]抛硬币 题解
这道题有神奇的多组数据, 沙雕的输出方式, 所以这里改下题面(当然把改过的题的做法稍稍修改下就可以AC原题)。
改过的题面:
给定\(a、b\) \(\ (1 \leq a,b \leq 10^{15}, b \leq a \leq b +10000)\)
求两个人\(A、B\)分别抛\(a、b\)次硬币, \(A\)抛出硬币正面朝上的总次数大于\(B\)抛出硬币正面朝上的总次数的情况有多少种, 答案对\(10^9\)取模。
说明
- 下文中\(W_A\)表示一种特定情况中\(A\)所抛硬币正面朝上的总次数, \(W_B\)类似。
- 下文中将一种特定情况看作两个分别长\(a、b\)的 \(01序列\) \(s_A、s_B\), 其中\(s_A\)代表\(A\)抛硬币的具体情况; 序列中的\(1\)表示正面朝上, \(0\)表示反面朝上。
先考虑\(a=b\)的情况。
考虑一个\(A\)胜利的情况, 此时将\(a=b, W_A>W_B\)。
\(s_A、s_B\)分别取反后, \(W_A = a-W_A, W_B = b-W_B\), 此时
\(W_A < W_B\), 取反后的\(s_A、 s_B\)对应着一种\(A\)败北的情况。
注意到一种\(A\)胜利的情况对应着唯一 一种\(A\)败北的情况且每一种\(A\)胜利的情况不会对应着同一种\(A\)败北的情况, 于是可以发现\(A\)胜利的情况数与\(A\)败北的情况数等值。
考虑\(A、B\)平手的情况数, 容易得出是\(\sum_{i=0}^a C_a^i C_a^i\), 套用范德蒙德卷积, 可以化简为\(C_{2a}^a\)。
结合 \(所有情况数 = A胜利情况数 + A败北情况数 + 平手情况数\)
可以算出\(a=b\)时的答案为
最后又一个要注意的地方, 就是\(2\)在膜\(10^9\)意义下是没有逆元的, 这时候就要优化一下式子。
首先将其拆开 :
手玩一下杨辉三角就可以发现\(C_{2a}^a\)必定是偶数, 并且
通过\(C_i^j = C_{i-1}^j + C_{i-1}^{j-1}\)算出\(C_{2a}^a\)时, \(C_{i-1}^j\) 与 \(C_{i-1}^{j-1}\)也是相同的,
故\(C_{2a}^a = 2*C_{2a-1}^a = 2*C_{2a-1}^{a-1}\)。
化简到这里就可以套\(exLucas\)算了。
再考虑\(a>b\)的情况。
考虑\(A\)胜利的一种情况, 由于\(a>b, W_A>W_B\), 所以此时将\(s_A、s_B\)分别取反后并不一定出现\(W_A < W_B\)的情况。
但是如果是\(A\)败北或平局的情况, 由于\(a>b\), \(W_A \leq W_B\), 则此时将\(s_A 、s_B\)分别取反后, 一定有\(W_A > W_B\)。
由此可以推出, 每个\(A\)不胜的情况, 将其\(s_A、s_B\)取反后,一定唯一对应一种\(A\)胜的情况。
再由于
(其中\(A不胜的情况数 = 与不胜情况有关的A胜的情况数\))
再由于\(总数\)为偶数, 故最后要算的就是:
继续考虑如何计算 \(与不胜情况无关的A胜的情况数\)。
发现如果一种\(A\)胜的情况与\(A\)不胜的情况无关, 那么其满足
整理得
然后就可以枚举\(W_A - W_B\)和\(W_B\)的值, 计算
化简一下
所以答案就是
然后\(\sum_{i=b+1}^{a-1} C_{a+b}^{i}\)要怎么除以二呢?
注意到\(a+b-(b-1) = a-1\), 结合\(C_{n+m}^m = C_{n+m}^n\), 可以发现
对于\(\sum_{i=b+1}^{a-1} C_{a+b}^{i}\)这个式子的每一个\(i\),都有\(a+b-i\)使得\(C_{a+b}^i = C_{a+b}^{a+b-i}\), 然后就可以除以2了。
但是注意到\(a+b\)为偶数的时候, \((a-1)-(b+1)+1\)是奇数,
怎么办?
研究了偶数所对的行在杨辉三角的构造后, 发现那个“处于中间的独身者”正好是\(C_{a+b}^{(a+b)/2}\), 于是就可以套用\(C_{2a}^a = 2*C_{2a-1}^a = 2*C_{2a-1}^{a-1}\), 于是就算完了。
这道题卡常, \(exLucas\)要写得精巧些。(太棒了, 学到许多)
Luogu&loj 数据AC代码:
#include<bits/stdc++.h>
using namespace std;
#define li long long
const int mod = 1000000000ll;
const li p1 = 512ll;
const li p2 = 1953125ll;
li ksm(li a, li b, li p) {
li res = 1ll;
for(;b;b>>=1, a=(a*a)%p)
if(b&1) res = (res*a)%p;
return res%p;
}
void exgcd(li a, li b, li &x, li &y) {
!b ? x=1,y=0 : (exgcd(b,a%b,y,x), y-=x*(a/b));
}
li inv(li a, li p) {
li x, y;
// ax + py = 1;
exgcd(a,p,x,y);
x = ((x%p+p)%p);
return x;
}
li TP2[605], TP5[2000005];
li fac(li n, li p, li pk) {
if(!n) return 1ll;
li res = p==2 ? TP2[pk] : TP5[pk];
res = ksm(res, n/pk, pk);
res *= p==2 ? TP2[n%pk] : TP5[n%pk];
res %= pk;
return fac(n/p,p,pk) * res % pk;
}
li C(li n, li m, li p, li pk) {
if(!m) return 1ll;
li cnt = 0ll;
for(li i=n;i;i/=p) cnt += i/p;
for(li i=m;i;i/=p) cnt -= i/p;
for(li i=n-m;i;i/=p) cnt -= i/p;
if(cnt > 9) return 0ll;
li f1 = fac(n,p,pk), f2 = fac(m,p,pk), f3 = fac(n-m,p,pk);
return f1 * inv(f2,pk) % pk * inv(f3,pk) % pk * ksm(p,cnt,pk) % pk;
}
li a1, a2;
li exlucas(li n, li m) {
a1 = C(n,m,2ll,p1);
a2 = C(n,m,5ll,p2);
li res = 0ll;
res += a1 * p2 % mod * inv(p2,p1) % mod;
res %= mod;
res += a2 * p1 % mod * inv(p1,p2) % mod;
res %= mod;
res = ((res%mod+mod)%mod);
return res;
}
void PRint(li ans, li k) {
li tmp = 100000000, num = 9;
while(tmp)
{
if(num<=k)
cout << ans/tmp;
ans %= tmp;
tmp /= 10;
--num;
}
putchar('\n');
}
int main()
{
TP2[0] = TP5[0] = TP2[1] = TP5[1] = 1ll;
for(li i=1; i<=p1; ++i)
TP2[i] = i%2 ? TP2[i-1]*i%p1 : TP2[i-1];
for(li i=1; i<=p2; ++i)
TP5[i] = i%5 ? TP5[i-1]*i%p2 : TP5[i-1];
li a, b, k;
while(scanf("%lld%lld%lld", &a, &b, &k) == 3) {
li ans = ksm(2,a+b-1,mod);
if(a==b) {
ans -= exlucas(2*a-1, a);
ans %= mod;
} else {
if((a+b)%2 == 0) {
for(li i=b+1; i<(a+b)/2; ++i) {
ans += exlucas(a+b,i);
ans %= mod;
}
ans += exlucas(a+b-1, (a+b)/2);
ans %= mod;
} else {
for(li i=b+1; i<=(a+b)/2; ++i) {
ans += exlucas(a+b,i);
ans %= mod;
}
}
}
ans = (ans%mod+mod)%mod;
PRint(ans, k);
}
return 0;
}