牛客练习赛13-B题(另带一份大佬的代码,细节值得学习)

题目链接:https://www.nowcoder.com/acm/contest/70/B

题目分析:把所有幸运数按从小到大都求出来,打个表。

代码:

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <string>
#include <stdlib.h>
#include <algorithm>

using namespace std;

long long lucky[100000],ans=0;
long long flag,flag1,sum=0,l,r;

int main()
{
    scanf("%lld%lld",&l,&r);
    lucky[sum++]=4;
    lucky[sum++]=7;
    lucky[sum++]=44;
    lucky[sum++]=47;
    lucky[sum++]=74;
    lucky[sum++]=77;
    flag=2;
    for(int i=3; i<=10; i++)
    {
            flag1=pow(2,i-1);
            for(int j=flag; j<flag+flag1; j++)
            {
                lucky[sum++]=lucky[j]*10+4;
                lucky[sum++]=lucky[j]*10+7;
            }
            flag+=pow(2,i-1);
    }


        long long  pos=l,j=l;
         for(long long  i=0; i<2046; )
         {
             if(j<=lucky[i])
             {
                 j++;
                 if(j==r+1)
                 {
                     ans=ans+(j-pos)*lucky[i];
                     break;
                 }
             }
             else
             {
                 ans=ans+(j-pos)*lucky[i];
                 pos=j;
                 i++;
                 if(j==r+1)
                    break;
             }

         }
       printf("%lld\n",ans);
    return 0;
}

分享一个大佬写的代码:http://blog.csdn.net/wyxeainn/article/details/79588812

代码如下:

解题思路:首先使用dfs求解出所有的幸运数字,题目给出  
数字数据范围为10亿,则最多10位由47组成的数字就是  
极限,对于每一位,可以是4,也可以是7,用递归进行计算,  
并保留所有的中间结果,一次递归的过程求出所有幸运数字。  
大概有一千多个,然后对他们进行排序,则对于给出的L,R,  
可以知道两个相邻幸运数字间的那些数字都对答案贡献较小  
的那个幸运数字,就这样跳着求。只要求出大于等于L幸运数  
字的位置,之后便不用查找,通过自增得来就可以了。  


变量含义:  
cnt:t数组的变量,在存储幸运数字时使用  
t:t数组用来存储所有的幸运数字  

方法含义:  
dfs:递归求幸运数字,dfs(x,num)x代表当前这位是x  
getNext:使用二分查找第一个大于等于i的幸运数字的位置  
***************************************************************************/  
#include <iostream>  
#include <stdio.h>  
#include <string.h>  
#include <algorithm>  

using namespace std;  

const long long maxn = 4444444444;  
long long cnt,t[1000];  
void dfs(int x,long long num) {  
   num = num*10 + x;  
   if(num > maxn) {  
        return;  
   }  
   t[cnt++] = num;  //存储中间的每一个数  
   dfs(4,num);  
   dfs(7,num);  
}  
int getNext(long long i){  
    int pos = lower_bound(t,t+cnt,i)-t;  
    return pos;  
}  
int main() {  
    cnt = 0;  
    dfs(4,(long long)0);  
    dfs(7,(long long)0);  
    //printf("%d\n",cnt);  
    sort(t,t+cnt); //排序,二分查找要求数组元素有序  
    long long L,R,temp;  
    while(~scanf("%lld%lld",&L,&R)) {  
        //防止L>R的情况,但本题此判断无用,因为题目说了L<=R  
        if(L>R) {  
            temp = L;  
            L = R;  
            R = temp;  
        }  
        long long ans = 0;  
        long long i = L;  
        long long x;  
        long long j = getNext(i);  //求起始位置。  
        while(true) {  
            x = t[j];  
            if(x >= R) {  
                ans += (R-i+1)*x;  
                break;  
            }  
            ans += (x-i+1)*x;  
            i = x+1;  
            j++;  
        }  
        printf("%lld\n",ans);  
    }  
    return 0;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值