【jzoj2175】幸运数

题目描述

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[i1]=0),那么当前幸运数 a [ i ] a[i] a[i]全赋为4并比前一个数多一位
  • 如果前一个数至少有一个4( t [ i − 1 ] > 0 t[i-1]>0 t[i1]>0),那么 a [ i ] a[i] a[i]分为三个处理:
    1、 t [ i − 1 ] t[i-1] t[i1]前的数与 a [ i − 1 ] a[i-1] a[i1]相等
    2、 a [ t [ i − 1 ] ] a[t[i-1]] a[t[i1]]赋为7
    3、 t [ i − 1 ] t[i-1] t[i1]后的数全部赋为4
幸运数474447
覆盖范围1~45~78~4445~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[i1],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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值