bzoj1853-大包子的幸运数字

题意

称只含有 6 和 8 的数字为幸运数字。称幸运数字的倍数为类幸运数字。求 \([l,r]\) 中有多少个类幸运数字。\(1\le l,r\le 10^{10}\)

分析

幸运数字最多有 \(2^{11}-2\) 个,先全部找出来,有倍数关系的留下最小的那个。容斥显然,关键是怎么写。

暴力dfs最小公倍数。

两个优化。第一,如果当前的最小公倍数已经大于 \(r\) 那么就退出。第二,所有幸运数字从大到小排序,这样不合法情况不用到最后才退出,大大降低时间。

复杂度:\(O(2^len(r)+不知道)\)

代码

以后写暴力要把不合法的条件在递归进去之前判掉。

最小公倍数会爆 long long ,所以需要用double来跟 \(r\) 比较。

#include<bits/stdc++.h>
using namespace std;
typedef long long giant;
const int maxl=2100;
giant l,r,b[maxl],a[maxl],ans=0;
bool no[maxl];
int m=0,n=0;
giant gcd(giant x,giant y) {
	return y?gcd(y,x%y):x;
}
void calc(int now,giant x,bool f) {
	if (now>n) {
		giant tmp=r/x-(l-1)/x;
		if (x!=1) ans+=(f?tmp:-tmp);
		return;
	}
	calc(now+1,x,f);
	giant tmp=(x/gcd(a[now],x));
	if ((double)tmp*a[now]<=r) calc(now+1,tmp*a[now],f^true);
}
void get(giant now) {
	if (now>r) return;
	if (now) b[++m]=now;
	get(now*10+6);
	get(now*10+8);
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
#endif
	cin>>l>>r;
	get(0);
	sort(b+1,b+m+1);
	for (int i=1;i<=m;++i) if (!no[i]) {
		a[++n]=b[i];
		for (int j=i+1;j<=m;++j) if (b[j]%b[i]==0) no[j]=true;
	}
	reverse(a+1,a+n+1);
	calc(1,1,false);
	cout<<ans<<endl;
	return 0;
}
posted @ 2017-08-16 20:32  permui  阅读(299)  评论(0编辑  收藏  举报