Petya喜欢Lucky Number。仅含有数字44和77的数字是一个Lucky Number。
规定next(x)next(x)等于最小的大于等于xx的Lucky Number。现在Petya想知道next(l)+next(l+1)+...+next(r-1)+next(r)next(l)+next(l+1)+...+next(r−1)+next(r)的值是多少。(1<=l<=r<=10^{9})(1<=l<=r<=109)
题目的意思就是只要含有4或7有其他数字就不行,除上一个幸运数字的前面,到本幸运数字
都赋值为这个幸运数字,详情请看这个图
会输入两个访问输出这两个访问中间的所有值
这里最先想到的是用前缀和来处理,但是怎么去处理,这就很棘手,给的范围很大,我们也无法去一个一个判断幸运数字。到这里对幸运数字的寻找就显得特别重要4 和7先列一下幸运数字
4 7 44 47 74 77 444 447 474 477
不是4就是7看第一个和第三个的关系*10+4,再看第二个和第四个的关系*10+7
int t=3;
lucky[1]=4;
lucky[2]=7;
for(int i=1;i<=2000;i++)
{
lucky[t++]=lucky[i]*10+4;
lucky[t++]=lucky[i]*10+7;
}
下一步对两个访问l,r的处理,我们唯一想的就是怎样把复杂度降到最低,对于l所对应的值是>=它的第一个幸运数(这里必是二分),对于r所对应的值为也是大于等于他的第一个幸运数,代码我想复杂了,我找的是小于等于他的最后一个数。对于前后边界特判处理一下就可以,对于中间的幸运数字不用前缀和,因为其特定区间内元素的值是相同的只需处理一下长度就行。
#include<iostream>
#include<algorithm>
#include<cstring>
#include <cmath>
#include<vector>
#define PII pair<int><int>
#define ll long long
#define endl "\n"
using namespace std;
const int N=1e5+10;
ll lucky[N];
ll sum=0,sum1,sum2;
ll x1,x2;
ll l,r;
ll RFl(int x)
{
int l1=0,r1=2000;
while(l1<r1)
{
ll mid=(l1+r1)>>1;
if(x<=lucky[mid]) r1=mid;
else l1=mid+1;
}
return l1;
}
ll RFr(int x)
{
int l1=0,r1=2000;
while(l1<r1)
{
ll mid=(l1+r1+1)>>1;
if(x>=lucky[mid]) l1=mid;
else r1=mid-1;
}
return l1;
}
void read_in()
{
cin>>l>>r;
}
void solve()
{
int t=3;
lucky[1]=4;
lucky[2]=7;
for(int i=1;i<=2000;i++)
{
lucky[t++]=lucky[i]*10+4;
lucky[t++]=lucky[i]*10+7;
}
x1=RFl(l),x2=RFr(r);
if(x1==x2+1) //说明在同一区间
{
sum=(r-l+1)*lucky[x1];
}
else
{
sum1=(lucky[x1]-l+1)*lucky[x1];
sum2=(r-lucky[x2])*lucky[x2+1];
sum=sum1+sum2;
int cha=x2-x1,k=x1;
k++;
while(cha--)
{
sum+=(lucky[k]-lucky[k-1])*lucky[k];
k++;
}
}
}
void expert_out()
{
cout<<sum;
//cout<<x1<<' '<<x2;
}
int main()
{
read_in();
solve();
expert_out();
return 0;
}
二分还得www.acwing.com