• BZOJ4830 [Hnoi2017]抛硬币 【扩展Lucas】


    题目链接

    BZOJ4830

    题解

    (a = b)时,我们把他们投掷硬币的结果表示成二进制,发现,当(A)输给(B)时,将二进制反转一下(A)就赢了(B)
    还要除去平局的情况,最后答案就是

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

    (a eq b)时,有些状态可能翻转后还是(A)(B),需要加上这部分

    [egin{aligned} sumlimits_{i = 0}^{b} sumlimits_{j = 1}^{a - b - 1}{b choose i} {a choose i + j} &= sumlimits_{j = 1}^{a - b - 1} sumlimits_{i = 0}^{b} {b choose b - i} {a choose i + j} \ &= sumlimits_{j = 1}^{a - b - 1} {a + b choose b + j} \ &= sumlimits_{j = b + 1}^{a - 1} {a + b choose j} \ end{aligned} ]

    答案是

    [frac{2^{a + b} + sumlimits_{j = b + 1}^{a - 1} {a + b choose j} }{2} ]

    (2)的处理,因为组合数是对称的,所以只算一半
    如果中间单独剩一个,一定可以被(2)整除,处理因子时减去一个即可

    由于要模(10^{K}),组合数的计算用扩展(Lucas)
    此题非常卡常,要使用扩展(Lucas)的一些优化
    1.预处理阶乘
    2.当(p)的幂次大于(k)时直接返回(0)
    3.没了

    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<iomanip>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<ctime>
    #include<cmath>
    #include<map>
    #define LL long long int
    #define REP(i,n) for (LL i = 1; i <= (n); i++)
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define cls(s,v) memset(s,v,sizeof(s))
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cp pair<int,int>
    using namespace std;
    const int maxn = 2000005,maxm = 100005,INF = 0x3f3f3f3f;
    int K,pr[2],pk[2],P,fac[2][maxn],now,ans;
    LL A,B;
    void init(){
    	pr[0] = 2; pr[1] = 5; pk[0] = pk[1] = P = fac[0][0] = fac[1][0] = 1;
    	REP(i,K) pk[0] *= 2,pk[1] *= 5,P *= 10;
    	for (LL i = 1; i < pk[0]; i++)
    		if (i % 2) fac[0][i] = 1ll * fac[0][i - 1] * i % pk[0];
    		else fac[0][i] = fac[0][i - 1];
    	for (LL i = 1; i < pk[1]; i++)
    		if (i % 5) fac[1][i] = 1ll * fac[1][i - 1] * i % pk[1];
    		else fac[1][i] = fac[1][i - 1];
    }
    inline int qpow(int a,LL b,int p){
    	int re = 1;
    	for (; b; b >>= 1,a = 1ll * a * a % p)
    		if (b & 1) re = 1ll * re * a % p;
    	return re;
    }
    inline void exgcd(int a,int b,int&d ,int& x,int& y){
    	if (!b){d = a; x = 1; y = 0;}
    	else exgcd(b,a % b,d,y,x),y -= (a / b) * x;
    }
    inline int inv(int n,int p){
    	int d,x,y; exgcd(n,p,d,x,y);
    	return (x % p + p) % p;
    }
    int Fac(LL n,int pk,int p){
    	if (!n) return 1;
    	return 1ll * qpow(fac[now][pk - 1],n / pk,pk) * fac[now][n % pk] % pk * Fac(n / p,pk,p) % pk;
    }
    int C(LL n,LL m,int pk,int p,bool f){
    	LL k = 0;
    	for (LL i = n; i; i /= p) k += i / p;
    	for (LL i = m; i; i /= p) k -= i / p;
    	for (LL i = n - m; i; i /= p) k -= i / p;
    	if (p == 2 && f) k--;
    	if (k >= 9) return 0;
    	now = (p == 5);
    	LL a = Fac(n,pk,p),b = Fac(m,pk,p),c = Fac(n - m,pk,p),ans;
    	ans = a * inv(b,pk) % pk * inv(c,pk) % pk;
    	if (p == 5 && f) ans = 1ll * ans * inv(2,pk) % P;
    	ans = ans * qpow(p,k,pk) % pk;
    	return ans * (P / pk) % P * inv(P / pk,pk) % P;
    }
    int exlucas(LL n,LL m,bool f){
    	if (m > n) return 0;
    	int re = 0;
    	re = (re + C(n,m,pk[0],pr[0],f)) % P;
    	re = (re + C(n,m,pk[1],pr[1],f)) % P;
    	return re;
    }
    int main(){
    	//double t = clock();
    	K = 9; init();
    	while (~scanf("%lld%lld%d",&A,&B,&K)){
    		ans = qpow(2,A + B - 1,P);
    		if (A == B) ans = ((ans - exlucas(A + B,A,1)) % P + P) % P;
    		else {
    			for (LL i = ((A + B) >> 1) + 1; i < A; i++){
    				ans = (ans + exlucas(A + B,i,0)) % P;
    			}
    			if ((A + B) % 2 == 0) ans = (ans + exlucas(A + B,(A + B) >> 1,1)) % P;
    		}
    		int md = qpow(10,K,INF); ans %= md;
    		while (ans < md / 10) putchar('0'),md /= 10;
    		printf("%d
    ",ans);
    	}
    	//cerr << (clock() - t) / CLOCKS_PER_SEC << endl;
    	return 0;
    }
    
    
  • 相关阅读:
    forkjoinpool
    json path
    如何处理json字符串
    ios如何快速转型安卓开发-专题3
    ios如何快速转型安卓开发-专题1
    framework创建及接入方式
    Cocoapods包管理
    cf 1102 B
    夜深人静写题解--杭电第五场
    夜深人静写题解--牛客第六场
  • 原文地址:https://www.cnblogs.com/Mychael/p/9292598.html
Copyright © 2020-2023  润新知