地址:http://www.lightoj.com/volume_showproblem.php?problem=1205
Time Limit: 2 second(s) | Memory Limit: 32 MB |
A palindromic number or numeral palindrome is a 'symmetrical' number like 16461 that remains the same when its digits are reversed. In this problem you will be given two integers i j, you have to find the number of palindromic numbers between i and j (inclusive).
Input
Input starts with an integer T (≤ 200), denoting the number of test cases.
Each case starts with a line containing two integers i j (0 ≤ i, j ≤ 1017).
Output
For each case, print the case number and the total number of palindromic numbers between i and j (inclusive).
Sample Input | Output for Sample Input |
4 1 10 100 1 1 1000 1 10000 | Case 1: 9 Case 2: 18 Case 3: 108 Case 4: 198 |
思路:通过确定第一位数字来确定最后一位数字,这样寻找一个数位为8的回文数可以通过确定第一位来寻找数位为6的回文数,以此类推。需要注意的是当首个数字为0是寻找的是有该数位数减1的数位的回文数,还有就是有些数字其第一位最大值在搜索时是达不到的,因为我们同时确定两位数,有可能另一位数达不到该位。做了一些数位DP的题,发现对于首位为0会有不同结果的题目来说,最好在自己要开的数组里多加一维来处理是否为前导0的情况。
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define LL long long
LL dp[25][2]; //多开一维处理是否为前导0的情况
int num[25],len1;
LL dfs(int len,int wz,bool p,bool z) //wz是确定目前考虑数字位置,z是确定是否有前导1
{
if(!len||len==-1) return 1;
if(!p&&~dp[len][z]) return dp[len][z];
LL ans=0;
if(!p) //对于不置顶的搜索可以直接进行
for(int i=0;i<=9;i++)
ans+=dfs(z|i?len-2:len-1,wz-1,0,z|i);
else //置顶的搜索可能会遇到例如1000的情况,即第1位可以确定为1,但最后一位不可以
{
int u=num[wz];
for(int i=0;i<u;i++)
ans+=dfs(z|i?len-2:len-1,wz-1,p&i==u,z|i);
if(num[wz]>num[len1-wz+1]) //如果本位以中心为轴对应的位置不能与本位同时达到极值
{
int j=2;
while(!num[len1-wz+j]&&len1-wz+j<=len1) j++; //寻找在本位以中心为轴对应的位置与本位之间不为0的位置
if(len1-wz+j>=wz) return ans; //找不到就直接返回ans
else
{
num[len1-wz+j]--; //该位置减一表示我从前面取一位
for(int i=len1-wz+j-1;i>=len1-wz+1;i--)
num[i]=9; //其余全置为9
}
}
ans+=dfs(z|u?len-2:len-1,wz-1,1,z|u); //找到就加上这一组搜索
}
if(!p) dp[len][z]=ans;
return ans;
}
LL getans(LL m)
{
if(m<0) return 0;
LL ans=0;len1=0;
for(;m;m/=10)
num[++len1]=m%10;
return dfs(len1,len1,1,0);
}
int main()
{
memset(dp,-1,sizeof(dp));
LL l,r;
int t,cas=1;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld",&l,&r);
if(l>r) {l^=r;r^=l;l^=r;} //注意本题可以小数在后
printf("Case %d: %lld\n",cas++,getans(r)-getans(l-1));
}
return 0;
}