2018.10.05 bzoj2393: Cirno的完美算数教室(容斥原理+搜索)

本文解析了一道经典的算法竞赛题目,通过分析题目特性,指出了解题关键在于处理数的倍数关系,并利用容斥原理与爆搜剪枝技巧求解。文章详细介绍了算法思路与实现代码,适合对算法竞赛感兴趣的学习者。

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

传送门
经典题目。
显然满足题意的数最多不超过1024个。
然后对于两个数 a , b a,b a,b,如果 a a a b b b的倍数,那么就不必计算 a a a的贡献。
处理出来之后容斥原理+爆搜剪枝就能过了。
代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll L,R,divv[1050],Div[1050],ans=0,f=1;
bool BK;
int tot=0,cnt=0;
inline void dfs(ll sum){
	if(sum>R)return;
	if(sum)divv[++tot]=sum;
	dfs(sum*10+2),dfs(sum*10+9);
}
inline ll gcd(ll a,ll b){while(b){ll t=a;a=b,b=t%a;}return a;}
inline void dfs(int pos,int dep,ll mul){
	if(mul>R)return;
	if(!dep){if(mul)ans+=f*(R/mul-(L-1)/mul),BK=0;return;}
	if(pos==cnt+1)return;
	dfs(pos+1,dep,mul),dfs(pos+1,dep-1,mul/gcd(mul,Div[pos])*Div[pos]);
}
int main(){
	cin>>L>>R,dfs(0),sort(divv+1,divv+tot+1);
	for(int i=1;i<=tot;++i){
		bool f=true;
		for(int j=i-1;j;--j)if(divv[i]%divv[j]==0){f=false;break;}
		if(f)Div[++cnt]=divv[i];
	}
	for(int i=1;i<=cnt;++i,f*=-1){
		BK=1,dfs(1,i,1);
		if(BK)break;
	}
	cout<<ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值