题解 P2567 [SCOI2010]幸运数字
大家好,我是 CQ-C2024 蒟蒻 CJH。
题意
“幸运号码”是十进制表示中只包含数字 $6$ 和 $8$ 的那些号码。
求:在 $[l,r]$ 中有多少个数能被“幸运号码”整除。
分析思路
注意:此题解非正解,如果要寻求正解请查看其他题解。
我这里提供另外一种相对于题解区中唯一一篇分块打标中不那么优雅的一种方法(空间换时间),事实证明,此方法和我其他同学(正解)的用时差不太多。
第一步:初始化所有的“幸运号码”
这里运用深度优先搜索 DFS 即可,先在 $1 \sim 10$ 中枚举位数,再来枚举每一位即可。
typedef long long LL;
LL a[2050];
int n=0;
void dfs(int pos,const int w,LL now){
if(pos>w){
a[++n]=now;
return;
}
dfs(pos+1,w,now*10+6);//此位为 6.
dfs(pos+1,w,now*10+8);//此位为 9.
}
int main(){
for(int i=1;i<=10;++i) dfs(1,i,0);/枚举位数。
}
代码
//the code is from chenjh
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL a[2050];
int n=0;
bitset <10000000001ll> s;
int b[]={26367832,26367734,26367442,26367629,26367812,26367617,26367927,26367701,26367894,26367822,26367654,26367735,26367803,26367794,26367559,26367726,26367750,26367792,26367674,26367746,26367638,26367697,26367596,26367707,26367764,26367734,26367678,26367714,26367601,26367494,26367657,26367706,26367747,26367778,26367761,26367733,26367761,26367630,26367541,26367672,26367754,26367672,26367713,26367761,26367807,26367659,26367749,26367779,26367847,26367681,26367701,26367687,26367728,26367686,26367740,26367683,26367677,26367638,26367715,26367669,26367758,26367742,26367822,26367737,26367773,26367725,26367831,26367682,26367895,26367670,26367770,26367681,26367695,26367788,26367613,26367802,26367646,26367729,26367696,26367743,26367697,26367720,26367652,26367762,26367758,26367614,26367941,26367729,26367817,26367830,26367679,26367788,26367737,26367685,26367735,26367847,26367682,26367814,26367737,26367755,1};
const int block=1e8;
void dfs(int pos,const int w,LL now){
if(pos>w){
a[++n]=now;
return;
}
dfs(pos+1,w,now*10+6);
dfs(pos+1,w,now*10+8);
}
LL solve(LL l,LL r){
// s.reset();
for(int i=1;i<=n;i++){
LL L=l/a[i],R=r/a[i];
for(LL j=L*a[i]<l?L+1:L;j<=R;++j)
s[j*a[i]]=1;
}
return s.count();
}
void test(){
// printf("%d\n",n);
// for(int i=1;i<=n;i++) printf("%lld ",a[i]);
freopen("temp.txt","w",stdout);
printf("{%lld,",solve(1,1e8-1));
for(LL l=1e8,r=2e8-1;l<r && r<=1e10;l=r+1,r+=1e8){
printf("%lld,",solve(l,r));
}
printf("%lld}",solve(1e10,1e10));
}
int main(){
for(int i=1;i<=10;++i) dfs(1,i,0);
// test();
LL l,r;
scanf("%lld%lld",&l,&r);
if(l==1 && r==1e10){
LL ans=0;
for(int i=0;i<=r/block;++i) ans+=b[i];
printf("%lld\n",ans);
return 0;
}
if(l/block==r/block){
printf("%lld\n",solve(l,r));
}
else{
LL ans=0;solve(l,(l/block+1)*block-1);
for(int i=l/block+1;i<r/block;i++)
ans+=b[i];
ans+=solve(r/block*block,r);
printf("%lld\n",ans);
}
return 0;
}