这道题有神奇的多组数据, 沙雕的输出方式, 所以这里改下题面(当然把改过的题的做法稍稍修改下就可以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('
');
}
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;
}