L题:回文数问题
题目描述
小小的大只没做中秋节热身赛,这两天看到那道回文数的题目颇为有趣。她决定进行修改。
输入格式:
题目有多组数据
每行两个数a,b,以空格隔开。
输出格式:
每行一个ans,表示[a,b]中回文数的个数。
sample in:
1 1
sample out:
1
数据范围:
0<a<=b且在int范围内.数据组数<=100000.
时限3s哦~~不卡cin,cout的时间
其实最开始的时候,感觉像这种带星号的附加题,应该也就是只有蔡大这样的大神才能去做的,不过后来渐渐发现,像那样的大神做这样的题可能对他们来说并不能达到挑战的级别,更多的是对于我们这些不是很厉害的同学,L题是一个可以锻炼自己能力,或者熟络整个之前自学的知识的好题,于是我也在21号下午开始尝试,结果用了整整一天的时间才做出来一个能Accept的答案。
首先,听左宗源说他的思路时候,用到了一些打表的语法(貌似是叫打表),但是不懂得打表究竟是什么。。。于是只能通过数学和C++的一些基本算法进行
基本算法:
-
要找出比输入数据x小的最近的回文数y
-
找出y与和y最近的1000…00数间存在的回文数数目(比如从10000到12345)
-
利用规律找出从1到1000…00数之间的所有回文数的数目
-
两者相加,则这就是总的回文数数目
-
将a,b分别求出从1到a-1,从1到b,的回文数数目,相减,所得结果即为所要求的数目
-
***特别的,奥数中有一个比较重要的回文数规律:
1~10 9
11~100 9
111~1000 90
1111~10000 90
…...
题目分析:题目要求中说,不卡cin,cout的时间,给了3s,看起来很大,实际上如果无脑循环,只是单纯的一个一个数去试,就会超时十几倍甚至几十倍,所以要想一个时间不长的方法,来避免超时错误
算法优势:1.这个解法并不是不使用循环,而是将循环的对象改为数的位数,也就是把每个循环次数限制在10以内。
2.利用设计出来的函数,减少了不必要的麻烦,计算简便。
3.所用语法比较初级(被我这个弱渣写成了大大的一坨)
算法缺陷:本算法应该会有更好,更简单的写法,我这次交的算法有些太繁杂,几乎不能在上机时候写完,所以只是能够利用这个算法熟络自己之前学的东西,并不一定能作为实用算法,所以。。。真心是仅供参考。。。。。。
为了实现这个问题,我将求出“1到x的回文数数目”的这几步骤汇合成为了一个函数
#include<iostream>
using namespace std;
int tens(int n) //定义一个函数表示10的n次方
{
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;
} //大功告成~