LOJ #2023. 「AHOI / HNOI2017」抛硬币(组合计数,拓展Lucas)

该博客探讨了LOJ #2023题目,涉及抛硬币问题的解决策略。通过反转每一位的值创建一一映射,然后计算可以建立映射的方案数量除以2,同时利用2的逆元巧妙处理。这是一个使用扩展Lucas定理的典型例子,适合作为理解该定理的实践题目。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目
有人讲得比我好
嗯,总的来说就是把情况通过反转每一位的值来建立一一映射。
建立映射之后就可以简单+不能建立映射的方案再/2了,
这个题对于2的逆元的处理十分巧妙,也可以当做一个不错的 e x L u c a s exLucas exLucas板题。

A C   C o d e \mathrm {AC \ Code} AC Code

#include<bits/stdc++.h>
#define LL long long
#define mod 1000000000
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
using namespace std;

void exgcd(int a,int b,int &x,int &y,int &gcd){ !b?(x=1,y=0,gcd=a):(exgcd(b,a%b,y,x,gcd),y-=a/b*x); }
struct factory{
	int fac[1953125],P,Pr;
	void init(int p,int pr){ fac[0]=1,P=p,Pr=pr;rep(i,1,p-1) fac[i]=i%pr?1ll*fac[i-1]*i%P:fac[i-1]; }
	int Pow(int b,int k){ int r=1;for(;k;k>>=1,b=1ll*b*b%P) if(k&1)r=1ll*r*b%P;return r; }
	int INV(int u){ int x,y,gd;exgcd(u,P,x,y,gd);return x; }
	int F(LL n){ return n?F(n/Pr)*1ll*fac[n%P]%P*Pow(fac[P-1],n/P)%P:1; }
	int C(LL n,LL m){
		int k=0;for(LL t=n;t;t/=Pr) k+=t/Pr;
		for(LL t=m;t;t/=Pr) k-=t/Pr;for(LL t=n-m;t;t/=Pr) k-=t/Pr;
		if(k >= 9) return 0;
		
		return 1ll * F(n) * INV(F(m)) % P * INV(F(n-m)) % P * Pow(Pr,k) % P;
	}
}f2,f5;
int C(LL n,LL m){
	int a=f2.C(n,m),b=f5.C(n,m),x,y,gd;
	exgcd(512,1953125,x,y,gd);
	return (a + 512ll * x % mod * (b-a)) % mod;
}
int Pow(int b,LL k){ int r=1;for(;k;k>>=1,b=1ll*b*b%mod) if(k&1) r=1ll*r*b%mod;return r; }
void print(int a,int k){ for(;k--;) printf("%d",a/Pow(10,k)%10);puts(""); }

int main(){
	LL a,b,k;
	f2.init(512,2),f5.init(1953125,5);
	for(;~scanf("%lld%lld%d",&a,&b,&k);){
		if(a == b) print((Pow(2,a+b-1)-C(2*a-1,a))%mod+mod,k);
		else{
			int ans = (Pow(2,a+b-1) + ((!((a+b)&1)) ? C(a+b-1,(a+b)/2) : 0)) % mod;
			rep(j,1,(a-b-1)/2) ans = (ans + C(a+b,b+j)) % mod;
			print((ans+mod)%mod,k);
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值