zoukankan      html  css  js  c++  java
  • [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)时的答案为

    [frac{2^{a+b} - C_{2a}^a}2 ag{% $10^9$} ]

    最后又一个要注意的地方, 就是(2)在膜(10^9)意义下是没有逆元的, 这时候就要优化一下式子。

    首先将其拆开 :

    [frac{2^{a+b}}2 - frac{C_{2a}^a}2 ]

    [=2^{a+b-1} - frac{C_{2a}^a}2 ]

    手玩一下杨辉三角就可以发现(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胜的情况数)

    再由于(总数)为偶数, 故最后要算的就是:

    [frac{2^{a+b} + 与不胜情况无关的A胜的情况数 }{2} ]

    继续考虑如何计算 (与不胜情况无关的A胜的情况数)
    发现如果一种(A)胜的情况与(A)不胜的情况无关, 那么其满足

    [a > b, W_A>W_B, a-W_A > b-W_B ]

    整理得

    [egin{cases} a-b geq 1\ W_A-W_B geq 1 \ W_A-W_B leq a - b - 1 end{cases} ]

    然后就可以枚举(W_A - W_B)(W_B)的值, 计算

    [sum_{i=1}^{a-b-1} sum_{j=0}^b C_a^{i+j} C_b^{j} ]

    化简一下

    [sum_{i=1}^{a-b-1} sum_{j=0}^b C_a^{i+j} C_b^{b-j} ]

    [=sum_{i=1}^{a-b-1} C_{a+b}^{b+i} ]

    [=sum_{i=b+1}^{a-1} C_{a+b}^{i} ]

    所以答案就是

    [frac{2^{a+b} + sum_{i=b+1}^{a-1} C_{a+b}^{i} }{2} ]

    然后(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;
    }
    
  • 相关阅读:
    服务器文档下载zip格式
    关于精度,模运算和高精的问题//19/07/14
    Luogu P2010 回文日期 // 暴力
    树形DP水题集合 6/18
    普通背包水题集合 2019/6/17
    因为时间少
    重学树状数组6/14(P3368 【模板】树状数组 2)
    Luogu P1291 [SHOI2002]百事世界杯之旅 // 易错的期望
    Luogu P4316 绿豆蛙的归宿//期望
    树剖
  • 原文地址:https://www.cnblogs.com/tztqwq/p/12732384.html
Copyright © 2011-2022 走看看