题目描述
4和7是味味的幸运数字。幸运数是那些只由幸运数字组成的正整数。如47,477是幸运数,而5,17,417 就不是幸运数。
定义next(x)为大于或等于x的最小的幸运数。
味味对以下表达式的值很感兴趣 :
next(L)+next(L+1)+…+next(R-1)+next®。
现在告诉你L和R的值,希望你能帮助味味计算出这个表达式的值。
输入
输入文件sum.in仅一行包含两个正整数L和R(1≤L≤R≤10^9 ),L和R的值之间用一个空格分隔。
输出
输出文件sum.out 只有一行一个整数,表示表达式的值。
样例输入
【样例输入1】
2 7
【样例输入2】
7 7
样例输出
【样例输出1】
33
【样例输出2】
7
数据范围限制
对于 20%的数据,1≤L≤R≤1000
对于 40%的数据,1≤L≤R≤10^6
另有20%的数据,L=R
对于 100%的数据,1≤L≤R≤10^9
提示
【样例 1 说明】
next(2)+next(3)+next(4)+next(5)+next(6)+next(7)=4+4+4+7+7+7=33
【样例 2 说明】
next(7)=7
解题思路
按题目的要求把所有幸运数按顺序求出来
(设
a
[
]
a[]
a[]存储幸运数,
t
[
]
t[]
t[]存储最后一个4的位置)
- 如果前一个数全是7( t [ i − 1 ] = 0 t[i-1]=0 t[i−1]=0),那么当前幸运数 a [ i ] a[i] a[i]全赋为4并比前一个数多一位
- 如果前一个数至少有一个4(
t
[
i
−
1
]
>
0
t[i-1]>0
t[i−1]>0),那么
a
[
i
]
a[i]
a[i]分为三个处理:
1、 t [ i − 1 ] t[i-1] t[i−1]前的数与 a [ i − 1 ] a[i-1] a[i−1]相等
2、 a [ t [ i − 1 ] ] a[t[i-1]] a[t[i−1]]赋为7
3、 t [ i − 1 ] t[i-1] t[i−1]后的数全部赋为4
幸运数 | 4 | 7 | 44 | 47 |
---|---|---|---|---|
覆盖范围 | 1~4 | 5~7 | 8~44 | 45~47 |
我们发现每个幸运数对答案的贡献
=
a
[
i
]
∗
(
m
i
n
(
a
[
i
]
,
R
)
−
m
a
x
(
a
[
i
−
1
]
,
L
)
)
=a[i]*(min(a[i],R)-max(a[i-1],L))
=a[i]∗(min(a[i],R)−max(a[i−1],L))
因为要处理很多细节,所以最好先把范围求出来再乘
a
[
i
]
a[i]
a[i]
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long a[3030],l,r,i,t[3030],x,s,b[30];
long long Gun;
void demo(int x){
long long s=a[x-1];
while(s>0){
a[x]=a[x]*10+4;//全赋为4
s/=10;
}
a[x]=a[x]*10+4;//并比前一个数多一位
}
void Grunt(int xx){
long long ss=a[xx-1];int j=1;
memset(b,0,sizeof(b));
while(j!=t[xx-1]){
b[j]=4;
if(b[j]==4&&t[xx]==0)t[xx]=j;
ss/=10;
j++;
}
//第一个处理
b[j]=7,ss/=10;
//第二个处理
while(ss>0){
j++;
b[j]=ss%10;
if(b[j]==4&&t[xx]==0)t[xx]=j;
ss/=10;
}
//第三个处理
for(;j>0;j--)
a[xx]=a[xx]*10+b[j];
//最后记得反过来
}
int main(){
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
scanf("%lld%lld",&l,&r);
for(i=1;i<=3000;i++)
if(t[i-1]==0)
demo(i),t[i]=1;//全是7
else
Grunt(i);//至少有一个4
x=l,i=1;while(a[i]<l)i++; //x表示求了x个数//i表示到第i个幸运数
while(x<=r){
s=min(a[i]-x,r-x)+1; //算出范围
x+=s,Gun+=s*a[i];
i++;
}
printf("%lld",Gun);
}