• 【BZOJ4830】[HNOI2017]抛硬币(组合计数,拓展卢卡斯定理)


    【BZOJ4830】[HNOI2017]抛硬币(组合计数,拓展卢卡斯定理)

    题面

    BZOJ
    洛谷

    题解

    暴力是啥?
    枚举(A)的次数和(B)的次数,然后直接组合数算就好了:(displaystyle sum_{i=0}^a{achoose i}sum_{j=0}^{i-1}{bchoose j})
    完美(TLE)
    先考虑特殊点的情况,如果(a=b),那么显然两者输赢的情况反过来是一一对应的,所以答案就是总情况减去平局的情况除二,而总方法就是(displaystyle 2^{a+b})。考虑平局的情况。枚举两个人正面朝上的个数就好了,也就是(displaystyle sum_{i=0}^a {achoose i}^2={2achoose a})
    证明?换个写法:(displaystyle sum_{i=0}^a {achoose i}{achoose a-i})。这样组合意义就很明显了,即把当前的(2a)个东西分成左右两半,要选(a)个出来,那么就枚举左半边选了几个,乘起来就好啦。
    好啦,上面怎么计算(a=b)的情况就很简单了,也就是(displaystyle frac{2^{2a}-{2achoose a}}{2})
    考虑怎么计算(a>b)的情况。我们前面(a=b)这么做的原因是什么呢?如果我们把一个非平局情况的整个抛硬币的结果全部翻转,那么必定对应这一种胜负情况相反的方案。
    但是现在(a>b),那么在(a-b)的这部分硬币可能存在一些正面,使得最终(A)仍然获胜。
    我们仍然想采用之前计算(a=b)的方法,总方案还是(2^{a+b}),然后我们直接除掉二,这样就会少算一些本来是(A)赢,翻转过来还是(A)赢的情况。所以要把这样的情况数给加上,再来除二。
    考虑这样的情况的方案数,假装(B)(x)个正面朝上,(A)正面朝上的次数是(y)。那么就要满足(b-x<a-y),也就是(a-b>y-x),因为本身就要(A)赢,所以还有(y>x)
    行,来枚举一下:(displaystyle sum_{i=0}^b{bchoose i}sum_{j=1}^{a-b-1}{achoose i+j})
    这是个什么鬼玩意???
    行,来重新写下:(sum_{j=1}^{a-b-1}displaystyle sum_{i=0}^b{bchoose b-i}{achoose i+j})
    恩,又来了,把东西分成左右两半,一共要选(j)个出来。
    所以式子这个玩意继续化简就是:(displaystyle sum_{j=1}^{a-b-1}{a+bchoose j})
    至于这个化简其实就是范德蒙德卷积。。。。。
    那就可以把答案式给写出来了:(displaystyle frac{2^{a+b}+sum_{j=1}^{a-b-1}{a+bchoose j}}{2})
    模数蛋疼无比,强行给套上一个拓展卢卡斯。
    然后就是各种卡常之旅了。这个东西除二肯定没有逆元,所以在算组合数的过程中就要除二。
    首先后面那个组合数发现(displaystyle {a+bchoose j}={a+bchoose a+b-j}),然后组合数又关于((a+b)/2)对称,所以组合数只需要算一半。
    然后如果(a+b)是偶数的话还需要特殊算(displaystyle{a+bchoose frac{a+b}{2}})
    注意一下组合数如果本身就要取模的话,就在算(5^k)的求逆,(2^k)的时候直接除二。。。
    我的代码又臭又长QwQ

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define ll long long
    inline ll read()
    {
    	ll x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int fpow(int a,int b){int s=1;while(b){if(b&1)s*=a;a*=a;b>>=1;}return s;}
    int fpow(int a,ll b,int MOD){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
    void exgcd(int a,int b,ll &x,ll &y){if(!b){x=1;y=0;return;}exgcd(b,a%b,y,x);y-=a/b*x;}
    int inv(ll n,ll m){ll x,y;exgcd(n,m,x,y);x=(x%m+m)%m;return x;}
    int fac[5],pw[5],tot=0;
    int jc[3][2000000];
    int JC(ll n,int p,int MOD,int id)
    {
    	if(!n)return 1;
    	int ret=JC(n/p,p,MOD,id);
    	if(n>MOD)ret=1ll*ret*fpow(jc[id][MOD]%MOD,n/MOD,MOD)%MOD,n%=MOD;
    	ret=1ll*ret*jc[id][n]%MOD;
    	return ret;
    }
    ll a,b;int k,P;int pw2,pw5;
    int C(ll n,ll m,int p,int pk,bool div)
    {
    	if(n<0||m<0||n<m)return 0;
    	ll zero=0;
    	for(ll i=n;i;i/=p)zero+=i/p;
    	for(ll i=m;i;i/=p)zero-=i/p;
    	for(ll i=n-m;i;i/=p)zero-=i/p;
    	if(p==2&&div)--zero;
    	if(zero>=k)return 0;
    	int a=JC(n,p,pk,1+(p==5));
    	int b=1ll*JC(m,p,pk,1+(p==5))*JC(n-m,p,pk,1+(p==5))%pk;
    	a=1ll*a*inv(b,pk)%pk*fpow(p,zero)%pk;
    	if(p==5&&div)a=1ll*a*(pk+1)/2%pk;
    	return 1ll*a*(P/pk)%P*inv(P/pk,pk)%P;
    }
    int exLucas(ll n,ll m,bool d){return (C(n,m,2,pw2,d)+C(n,m,5,pw5,d))%P;}
    void output(int x)
    {
    	if(k==1)printf("%.1d
    ",x);if(k==2)printf("%.2d
    ",x);if(k==3)printf("%.3d
    ",x);
    	if(k==4)printf("%.4d
    ",x);if(k==5)printf("%.5d
    ",x);if(k==6)printf("%.6d
    ",x);
    	if(k==7)printf("%.7d
    ",x);if(k==8)printf("%.8d
    ",x);if(k==9)printf("%.9d
    ",x);
    }
    int main()
    {
    	fac[1]=2;fac[2]=5;pw[1]=pw[2]=9;tot=2;
    	for(int i=1;i<=tot;++i)
    	{
    		int MOD=fpow(fac[i],pw[i]);jc[i][0]=1;
    		for(int j=1;j<=MOD;++j)jc[i][j]=1ll*jc[i][j-1]*(j%fac[i]?j:1)%MOD;
    	}
    	while(scanf("%lld%lld%d",&a,&b,&k)!=EOF)
    	{
    		P=fpow(10,k);pw[1]=pw[2]=k;pw2=fpow(2,k);pw5=fpow(5,k);
    		int ans=fpow(2,a+b-1,P);
    		if(a==b)ans=(ans+P-exLucas(a+b,a,1))%P;
    		else
    		{
    			for(ll i=(a+b)/2+1;i<a;++i)
    				ans=(ans+exLucas(a+b,i,0))%P;
    			if((a+b)%2==0)ans=(ans+exLucas(a+b,(a+b)/2,1))%P;
    		}
    		output(ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    8.9_java_35
    8.8_java_34
    8.7_java_33
    8.6_java_32
    8.5_java_31
    8.4_java_30
    8.3_java_29
    2020年春季学期《软件工程》教学总结
    json的标准格式
    详解 【Vue】 生命周期
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10179890.html
Copyright © 2020-2023  润新知