来源:牛客网
思路:选或不选/选1还是选2,且遍历的范围很小(<20)-->先用DFS遍历获得所有结果(当然可以剪枝,即超过r的数字最多只保留一个就行)存储到数组中
题目描述
定义一个数字为幸运数字当且仅当它的所有数位都是4或者7。
比如说,47、744、4都是幸运数字而5、17、467都不是。
定义next(x)为大于等于x的第一个幸运数字。给定l,r,请求出next(l) + next(l + 1) + ... + next(r - 1) + next(r)。
比如说,47、744、4都是幸运数字而5、17、467都不是。
定义next(x)为大于等于x的第一个幸运数字。给定l,r,请求出next(l) + next(l + 1) + ... + next(r - 1) + next(r)。
输入描述:
两个整数l和r (1 <= l <= r <= 1000,000,000)。
输出描述:
一个数字表示答案。
然后仔细观察数据,会发现:
a next(a)
0 0
1 4
2 4
3 4
4 4
5 7
6 7
7 7
8 44
...
以样例1的2,7为例,推算一下,会发现,ans=(4-2+1)*4+(7-4)*7;
再多带几组数据进去,就能推出下面代码中的式子(标红部分)
总体难度不难,DFS很常规,唯一难一点的可能就是底下ans的推导了
这里贴一道相似的问题,也是类似于选或不选/选1还是选2,且遍历的范围很小(<20)的问题:1008-「金」点石成金_2021秋季算法入门班第六章习题:搜索与搜索剪枝
代码如下
#include<bits/stdc++.h>
#define ll long long int
using namespace std;
ll l,r,ans;
vector<ll>q; //用于存储含4和7的数字
void DFS(int i){
q.push_back(q[i]*10+4);
if((q[i]*10+4)>=r) return ; //剪枝
q.push_back(q[i]*10+7);
if((q[i]*10+7)>=r) return ; //剪枝
DFS(i+1);
}
int main(){
scanf("%lld%lld",&l,&r);
q.push_back(0);
DFS(0);
int n=q.size();
int i=0;
while(q[i]<l){ //这里遍历是不会超时的,因为r最大为1000,000,000,即q里面的数字的数量最多不超过2^10+1;
i++;
}
ans+=((min(r,q[i])-l+1)*q[i]);
while(q[i]<r){
ans+=((min(r,q[i+1])-max(q[i],l))*q[i+1]);
i++;
}
printf("%lld\n",ans);
return 0;
}
#define ll long long int
using namespace std;
ll l,r,ans;
vector<ll>q; //用于存储含4和7的数字
void DFS(int i){
q.push_back(q[i]*10+4);
if((q[i]*10+4)>=r) return ; //剪枝
q.push_back(q[i]*10+7);
if((q[i]*10+7)>=r) return ; //剪枝
DFS(i+1);
}
int main(){
scanf("%lld%lld",&l,&r);
q.push_back(0);
DFS(0);
int n=q.size();
int i=0;
while(q[i]<l){ //这里遍历是不会超时的,因为r最大为1000,000,000,即q里面的数字的数量最多不超过2^10+1;
i++;
}
ans+=((min(r,q[i])-l+1)*q[i]);
while(q[i]<r){
ans+=((min(r,q[i+1])-max(q[i],l))*q[i+1]);
i++;
}
printf("%lld\n",ans);
return 0;
}