北京航空航天大学online judge:2014第一次练习*L题



L题:回文数问题

 

题目描述

小小的大只没做中秋节热身赛,这两天看到那道回文数的题目颇为有趣。她决定进行修改。

输入格式:

题目有多组数据
每行两个数ab,以空格隔开。

输出格式:

每行一个ans,表示[a,b]中回文数的个数。

sample in

1 1

sample out

1

数据范围:

0<a<=b且在int范围内.数据组数<=100000.

时限3s~~不卡cin,cout的时间

 

 

其实最开始的时候,感觉像这种带星号的附加题,应该也就是只有蔡大这样的大神才能去做的,不过后来渐渐发现,像那样的大神做这样的题可能对他们来说并不能达到挑战的级别,更多的是对于我们这些不是很厉害的同学,L题是一个可以锻炼自己能力,或者熟络整个之前自学的知识的好题,于是我也在21号下午开始尝试,结果用了整整一天的时间才做出来一个能Accept的答案。

首先,听左宗源说他的思路时候,用到了一些打表的语法(貌似是叫打表),但是不懂得打表究竟是什么。。。于是只能通过数学和C++的一些基本算法进行

 

基本算法:

  1. 要找出比输入数据x小的最近的回文数y

  2. 找出y与和y最近的1000…00数间存在的回文数数目(比如从1000012345

  3. 利用规律找出从11000…00数之间的所有回文数的数目

  4. 两者相加,则这就是总的回文数数目

  5. a,b分别求出从1a-1,1b,的回文数数目,相减,所得结果即为所要求的数目

  6. ***特别的,奥数中有一个比较重要的回文数规律:

    1~10            9

    11~100          9

    111~1000       90

    1111~10000         90

       …...

        

题目分析:题目要求中说,不卡cin,cout的时间,给了3s,看起来很大,实际上如果无脑循环,只是单纯的一个一个数去试,就会超时十几倍甚至几十倍,所以要想一个时间不长的方法,来避免超时错误

 

算法优势:1.这个解法并不是不使用循环,而是将循环的对象改为数的位数,也就是把每个循环次数限制在10以内。

                     2.利用设计出来的函数,减少了不必要的麻烦,计算简便。

                     3.所用语法比较初级(被我这个弱渣写成了大大的一坨)

 

 

算法缺陷:本算法应该会有更好,更简单的写法,我这次交的算法有些太繁杂,几乎不能在上机时候写完,所以只是能够利用这个算法熟络自己之前学的东西,并不一定能作为实用算法,所以。。。真心是仅供参考。。。。。。

 

 

为了实现这个问题,我将求出“1x的回文数数目”的这几步骤汇合成为了一个函数

#include<iostream>

using namespace std;

int tens(int n)              //定义一个函数表示10n次方

{

    int a=1;

    for(int i=1;i<=n;i++)

    {

        a=a*10;

    }

    return a;

}

int f1(int x)                  //本解法核心:表示找出一个数与其相距最近的形如100000...000的数间,包含回文数的数目

{

    int a[20];

    int b[20];

    intcounter1=1,counter2=1,counter3=1,k=0,n,i=1,r,temp1,temp2;

    temp1=x;

    temp2=x;

    while(temp1!=0)      //分割x的所有位并储存

    {

       a[counter1]=temp1-temp1/10*10;

        temp1=temp1/10;

        counter1++;

    }

    counter1--;

    counter2=counter1;

    r=counter2;         //两个都是位数

   while(counter1>counter3)

    {

 

        counter1--;

        counter3++;

    }

   while(counter2>counter1)

    {

        a[i]=a[counter2];

        i++;

        counter2--;

    }

    counter2=r;

   for(i=1;i<=counter2;i++)

    {

        k=tens(i-1)*a[i]+k;                            //此时的K是指与其最近的回文数,目的是求数目。。。

    }

    counter1--;

   //cout<<"counter1 "<<counter1<<endl;

    int counter4=0;

    while(temp2>0)

    {

        temp2=temp2/10;

        counter4++;

    }

   //cout<<counter4<<endl;

    //cout<<"k"<<k<<endl;                                                           //这部分是判断下,刚才输出的距离最近的回文数是否比他小,如果不是将其改为最近且最近且最小的

    if(counter4%2!=0)

    {

 

        if(k<=x)

        {

           n=k/tens(counter1)-tens(counter1)+1;           //需要分析数的位数:需要分奇偶判断

        }

        else

        {

           k=k-tens(counter1);

           //cout<<"修改之后的数 "<<k<<endl;

            n=k/tens(counter1)-tens(counter1)+1;

        }

    }

    else

    {

        if(k<=x)

        {

           n=k/tens(counter1+1)-tens(counter1)+1;

        }

        else

        {

            int temp3;

            temp3=k;

            int y=1;

            while(temp3/(counter4-1)==0)

            {

               temp3=k-tens(counter1+y)-tens(counter1+1-y);

                y++;

            }

           n=temp3/tens(counter1+1)-tens(counter1);

        }

    }

    return n;                  //输出的是所要求的个数

}

int f2(intx)                                      //此函数是求1~10...00的回文数个数

{

    int counter1=-1,nu;

    while(x>0)

    {

        x=x/10;

        counter1++;

    }

    switch(counter1)

     {

        case 0:

            nu=0;

            break;

        case 1:

            nu=9;

            break;

        case 2:

            nu=18;

            break;

        case 3:

            nu=108;

            break;

        case 4:

            nu=198;

            break;

        case 5:

            nu=1098;

            break;

        case 6:

            nu=1998;

            break;

        case 7:

            nu=10998;

            break;

        case 8:

            nu=19998;

            break;

        case 9:

            nu=109998;

            break;

        case 10:

            nu=199998;

            break;

     }

 

    return nu;

}

 

intcountPN(int x)                  //将之前的函数汇总,找出从“1”到输入数据间所有的回文数数目

{

    int number;

    if(x==0)

    {

        number=0;

    }

    else

    {

        number=f1(x)+f2(x);

    }

    return number;

 

}

 

 

intmain()                                        //输入a,b,分别找出"1""a-1""1""b"的回文数数目,相减,即为回文数数目

{

    int a,b,sum;

   while(cin>>a>>b)

    {

       sum=countPN(b)-countPN(a-1);

       cout<<sum<<endl;

    }

    return 0;

}                                                       //大功告成~

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值