[SCOI2010]幸运数字

link

很简单的容斥题。考场上想出正解,然后写挂了。死因:实现方法想多了。

就很简单,枚举所有幸运号码(可以证出大概两千个),把有倍数关系的提取出来删掉大的,这样肯定不会影响答案,然后做容斥即可。实现过程直接爆搜即可,甚至不用剪枝,因为这些数毕竟有那么大,几次lcm之后就可以顺利地超过1e10.要注意的是lcm的过程可能会爆龙龙宝宝,要判一下。没什么了。

倒序之后是跑得更快,但不倒序也可以卡过,时间上倒是有8倍差距。

#include<bits/stdc++.h>
//#define feyn
#define int long long
const int N=10010;
const int maxn=1e18;
const int S=1e12;
using namespace std;
inline void read(int &wh){
	wh=0;int f=1;char w=getchar();
	while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
	while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
	wh*=f;return;
}

int l,r,a[N],num;
void find(int wh){
	if(wh>r)return;
	if(wh)a[++num]=wh;
	find(wh*10+6);find(wh*10+8);
}

inline int gcd(int s1,int s2){
	return s2==0?s1:gcd(s2,s1%s2);
}
inline int lcm(int s1,int s2){
	if(s1>maxn/s2)return S;
	return s1/gcd(s1,s2)*s2;
}

int ans;
void dfs(int wh,int val,int c){
	if(val>1&&val<=r)ans+=c*(r/val-l/val);
	if(wh>num||val>r)return;
	for(int i=wh;i<=num;i++){
		dfs(i+1,lcm(val,a[i]),-c);
	}
}

inline bool cmp(int s1,int s2){
	return s1>s2;
}

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	read(l);read(r);find(0);l--;
	sort(a+1,a+num+1);
	int ss=0;
	for(int i=1;i<=num;i++){
		if(a[i]==0)continue;
		a[++ss]=a[i];
		for(int j=i+1;j<=num;j++){
			if(a[j]%a[i]==0)a[j]=0;
		}
	}
	num=ss;
	sort(a+1,a+num+1,cmp);
	dfs(1,1,-1);
	printf("%lld",ans);
	
	return 0;
}
posted @ 2022-07-11 14:40  Feyn618  阅读(22)  评论(0编辑  收藏  举报