不要62

不要62

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 55413    Accepted Submission(s): 21347


 

Problem Description

杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。

 

 

Input

输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。

 

 

Output

对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。

 

 

Sample Input

 

1 100 0 0

 

 

Sample Output

 

80

 

 

Author

qianneng

 

 

Source

迎接新学期——超级Easy版热身赛

 

 

Recommend

 

先上一个超时的代码:

#include<stdio.h>
#include<math.h>

int main()
{
    int n,m;
    int a[8];
    while(~scanf("%d %d",&n,&m),m||n)
    {
        int i,j=0,t,p,f=0,k=0;
        for(i=n;i<=m;i++)
        {
            t=i;f=0;
            j=0;
            while(t!=0)
            {
                a[j]=t%10;
                //printf("a[%d]:%d\n",j,a[j]);   需要电脑在线判断,感觉比较麻烦,遂卒
                t/=10;
                j++;
            }
            
            for(p=0;p<j;p++)
            {
                if(a[p]==4||(a[p]==2&&a[p+1]==6))
                {
                    f=1;
                    break;
                }
            }
            //printf("%d\n\n",f);
            if(f==1)
            continue;
            else
            k++;
            
            
        }
        printf("%d\n",k);
    }
    return 0;
}

 

最朴素的算法就是枚举n-m之间的所有数字进行在线判断。
判断可以利用itoa把数字转化成字符串,利用字符串函数strstr快速判断之后输出答案,再继续搜索下一个n-m


但是我们考虑一个问题。由于本题目没有提问组数的范围,考虑一个极端情况,询问100000次1-1000000

很显然,肯定是会超时的。



因此我们考虑来离线回答这个问题,也就是预处理。我们知道,如果在线回答100000次1-1000000就意味着要做100000次1-1000000的循环,那么我们提前在回答前就算好并记录好答案,然后询问的话只要直接输出就行了。


那么怎么预先算好呢?很简单,读入前先做一次1-1000000的循环,建立一个数组a,记录前i个数有几个是不符合的。也就是利用了前缀和。这样的话后面读入n与m后,我们只需要a[m]-a[n]能在o(1)的复杂度内就知道n-m内不符合的数字,同时计算出答案。这样就绝对不会超时了。



可能有萌新不知道前缀和。我一开始也不知道,但是其实自己一直在用,后来才被告知这叫前缀和= =

举个例子,1 2 3 4 5 6 7 8 9我想知道任意区间[n,m]的值,我们读入的时候不要存一个数,而是把前I项存起来。

存完是这样的1 3 6 10 15 21 28 36 45,如果我想知道[2,10]内数字的和,就直接a[10]-a[2-1]即可,不需要循环了。

 

 

 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int a[1000010];
char str[1000010];
int main()
{
    
    
    int n,m;
    int i,j;
    memset(a,0,sizeof(a[0]));
    for(i=1;i<1000001;i++)  //用数组统计从1到下标之间的含不符合条件的个数 
    {
        itoa(i,str,10);
        if(strstr(str,"4")!=NULL)
        {
            a[i]=a[i-1]+1;
            continue;
        }
        if(strstr(str,"62")!=NULL)
        {
            a[i]=a[i-1]+1;
            continue;
        }
        a[i]=a[i-1];//如果没有出现62和4,则跟前一个一样。 
    }//统计完毕 
    while(~scanf("%d %d",&n,&m),m||n)
    {
        printf("%d\n",m-n+1-(a[m]-a[n-1]));
    }
    return 0;
 } 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值