您的位置:首页 > 其它

[SCOI2010]幸运数字

2017-03-26 17:54 127 查看

题目背景

四川NOI省选2010

题目描述

在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认为,于是他定义自己的“幸运号码”是十进制表示中只包含数字6和8的那些号码,比如68,666,888都是“幸运号码”!但是这种“幸运号码”总是太少了,比如在[1,100]的区间内就只有6个(6,8,66,68,86,88),于是他又定义了一种“近似幸运号码”。lxhgww规定,凡是“幸运号码”的倍数都是“近似幸运号码”,当然,任何的“幸运号码”也都是“近似幸运号码”,比如12,16,666都是“近似幸运号码”。

现在lxhgww想知道在一段闭区间[a, b]内,“近似幸运号码”的个数。

输入输出格式

输入格式:

输入数据是一行,包括2个数字a和b

输出格式:

输出数据是一行,包括1个数字,表示在闭区间[a, b]内“近似幸运号码”的个数

输入输出样例

输入样例#1:

1 10


输出样例#1:

2


说明

对于30%的数据,保证1<=a<=b<=1000000

对于100%的数据,保证1<=a<=b<=10000000000

思路:打表+容斥原理+剪枝

先打一张幸运数字的表;

然后容斥原理求值;

剪枝:有些(是前面的幸运数字的倍数)幸运数字是无用的。

从大到小排。

超出边界的最小公倍数是无用的。

代码实现:

#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
LL l,r,ans;
LL a,b;
LL s[3000],ss;
LL fs[3000],fss;
LL lch,ret;
char ch[30];
LL read(){
while(ch[0]=getchar(),ch[0]<'0'||ch[0]>'9');
lch=1,ret=ch[0]-'0';
while(ch[lch]=getchar(),ch[lch]>='0'&&ch[lch]<='9') ret=ret*10+ch[lch]-'0',lch++;
return ret;
}
void write(LL x){
if(!x) return;
write(x/10);
putchar(x%10+'0');
}
void dfs(LL x){
if(x>r) return;
if(x) s[ss++]=x;
dfs(x*10+6);
dfs(x*10+8);
}
inline LL gcd(LL x,LL y){return y?gcd(y,x%y):x;}
void get_ans(LL k,LL x,LL y){
if(x>r) return;
if(k) ans+=(k&1)?r/x-(l-1)/x:(l-1)/x-r/x;
for(LL i=y;i<ss;i++){
LL t=x/gcd(x,s[i]);
if(t<=r/s[i]) get_ans(k+1,t*s[i],i+1);
}
}
int main(){
freopen("luckynumber.in","r",stdin);
freopen("luckynumber.out","w",stdout);
l=read(),r=read();
dfs(0);
sort(s,s+ss);
for(LL i=0;i<ss;i++){
for(LL j=0;j<fss;j++)
if(s[i]%fs[j]==0){s[i]=0;break;}
if(s[i]) fs[fss++]=s[i];
}
ss=fss;
for(int i=0;i<ss;i++) s[i]=fs[ss-i-1];
get_ans(0,1,0);
if(!ans) putchar('0');
write(ans);
putchar('\n');
return 0;
}


bzoj741950429J_william
872 KB672 MS1188 B2017-03-26 18:04:28
LONG LONG 真恶心!

题目来源:洛谷,bzoj
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: