[BZOJ1853][Scoi2010]幸运数字 容斥+搜索剪枝
1853: [Scoi2010]幸运数字
Time Limit: 2 Sec Memory Limit: 64 MBSubmit: 3202 Solved: 1198
[Submit][Status][Discuss]
Description
在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认为,于是他定义自己的“幸运号码”是十进制表示中只包含数字6和8的那些号码,比如68,666,888都是“幸运号码”!但是这种“幸运号码”总是太少了,比如在[1,100]的区间内就只有6个(6,8,66,68,86,88),于是他又定义了一种“近似幸运号码”。lxhgww规定,凡是“幸运号码”的倍数都是“近似幸运号码”,当然,任何的“幸运号码”也都是“近似幸运号码”,比如12,16,666都是“近似幸运号码”。 现在lxhgww想知道在一段闭区间[a, b]内,“近似幸运号码”的个数。
Input
输入数据是一行,包括2个数字a和b
Output
输出数据是一行,包括1个数字,表示在闭区间[a, b]内“近似幸运号码”的个数
Sample Input
【样例输入1】
1 10
【样例输入2】
1234 4321
1 10
【样例输入2】
1234 4321
Sample Output
【样例输出1】
2
【样例输出2】
809
2
【样例输出2】
809
HINT
【数据范围】
对于30%的数据,保证1 < =a < =b < =1000000
对于100%的数据,保证1 < =a < =b < =10000000000
Source
考虑由6和8组成的数很少,枚举。
之后去掉互为倍数的数。
把这些数从大到小排序加快搜索增长速度。
最小公倍数>r时退出。(可能爆long long运用double判断)
容斥。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<cmath> 6 #include<algorithm> 7 #define LL long long 8 #define maxn 500005 9 using namespace std; 10 LL read() { 11 LL x=0;char ch=getchar(); 12 for(;!isdigit(ch);ch=getchar()) ; 13 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0'; 14 return x; 15 } 16 LL a[maxn],l,r,tot; 17 LL gcd(LL x,LL y) {return y==0?x:gcd(y,x%y);} 18 void make(LL x){ 19 if(x>r) return ; 20 if(x>0) a[++tot]=x; 21 make(x*10+6); 22 make(x*10+8); 23 } 24 LL ans=0; 25 void solve(LL x,LL now,LL val) { 26 if(x==tot+1) { 27 if(!now||!val) return; 28 if(now&1) ans+=r/val-(l-1)/val; 29 else ans-=r/val-(l-1)/val; 30 return ; 31 } 32 solve(x+1,now,val); 33 34 if(!now){solve(x+1,now+1,a[x]);return;} 35 LL nn=gcd(val,a[x]); 36 if((double)a[x]*val/nn>r) return; 37 solve(x+1,now+1,a[x]*val/nn); 38 } 39 int main() { 40 l=read(),r=read(); 41 make(0); 42 sort(a+1,a+tot+1); 43 for(int i=1;i<=tot;i++) { 44 if(!a[i]) continue; 45 for(int j=i+1;j<=tot;j++) if(a[j]%a[i]==0) a[j]=0; 46 } 47 LL tmp=tot;tot=0; 48 for(int i=1;i<=tmp;i++) if(a[i]) a[++tot]=a[i]; 49 for(int i=1;i<=tot/2;i++) swap(a[i],a[tot-i+1]); 50 solve(1,0,0); 51 printf("%lld\n",ans); 52 }
O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~