Palindromic Numbers(数位dp)

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

4

1 10

100 1

1 1000

1 10000

Sample Output

Case 1: 9

Case 2: 18

Case 3: 108

Case 4: 198


虽然说是数位dp,但是我的做法却是不伦不类的,但是自己感觉还是蛮有趣的,就在这里记录一下吧;

题目大意:

给你i,j求两个数之间回文数的个数,注意前导零;

思路:

一.既然是求i,j之间的个数,还是老套的求f(j)-f(i-1);


二.利用dp[i]表示所有i位的数有多少回文数(例如i=3时,保存100到999之间的回文数),这也是我用到的全部数位dp了;

那么要如何保存呢,分奇数位偶数位两种情况:

偶数位如果保证回文,要求对称,如果是i位数,前i/2位要对称于后i/2位,

例如四位数,前2位数字有10到99共有90种情况,所以四位数共有90个回文数;

奇数位相当于在少一位的偶数位中间插入一个数,这个数可以是0到9共10个数任意一个;

例如五位数,中间不考虑就是有90种情况,这时考虑中间数有10种,所以共有90*10种情况;

得到递推公式:

if(i%2)
    dp[i]=dp[i-1]*10;
else
    dp[i]=num[i/2];
ps:int num[20]={0,9,90,900,9000,90000,900000,9000000,90000000};
因为num知道,所以直接写了个数组存;

注意0也是回文数,所以dp[1]=10;


三.分步求结果,感觉更像数学公式,这里拿34512这个数字举例子:

1.利用递推公式可知0~9999共有dp[1]+dp[2]+dp[3]+dp[4]个;

2.开始计算10000~34512;

(1)先拆分3451234 5 12

(2)则前两位为10~33时共33-9种情况时共有(33-9)*10个回文数,此时中间数可以为0~9,后两位可以是任何组合;

(3)前两位为34时,考虑中间数,有0~4共5种情况,此时后两位可以是任何组合;

(4)前两位为34,中间为5时,比较最后两位与前两位的对称数,因为此时只有34543是回文数,但是12比43小,达不到43,那么这种情况就不算;

3.于是最后结果就是dp[1]+dp[2]+dp[3]+dp[4]+(33-9)*10+5+0,四步合一得到最终结果;

4.偶数位同理,但是不考虑中间数罢了;


代码(代码很杂乱,思路也不算清晰,写到哪里想到哪里,不打推荐看代码,容易绕晕,但是只要掌握上面方法就很容易弄清了):

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long LL;
int num[20]={0,9,90,900,9000,90000,900000,9000000,90000000};
int first0[20]={0,0,9,99,999,9999,99999,999999,9999999}; //多余的含前导零数
LL dp[20];
struct huiwen
{
        int l,fl,mid,r,flag,len;//flag=0为偶数 =1为奇数  fl存储的是前几个数的对称数
}h;
LL solve()
{
        LL i,sum=0;
        for(i=1;i<h.len;i++)
        {
                sum+=dp[i];
        }
        if(h.flag)
        {
                sum+=((h.l-1-first0[h.len/2])*10+h.mid);
                if(h.fl<=h.r)
                        sum++;
        }
        else
        {
                sum+=(h.l-1-first0[h.len/2]);
                if(h.fl<=h.r)
                        sum++;
        }
        return sum;
}
int putin(LL x)
{
        int a[20],i=0,m;
        while(x)
        {
                a[++i]=x%10;
                x/=10;
        }
        m=(i+1)/2;
        h.l=h.r=h.fl=0;
        h.len=i;
        if(i%2)
        {
                h.flag=1;
                h.mid=a[m];
                for(;i>m;i--)
                        h.l=(h.l*10+a[i]);
                for(i=m+1;i<=h.len;i++)
                        h.fl=(h.fl*10+a[i]);
                for(i=m-1;i>=1;i--)
                        h.r=(h.r*10+a[i]);
        }
        else
        {
                h.flag=0;
                for(;i>m;i--)
                        h.l=(h.l*10+a[i]);
                for(i=m+1;i<=h.len;i++)
                        h.fl=(h.fl*10+a[i]);
                for(i=m;i>=1;i--)
                        h.r=(h.r*10+a[i]);
        }
        return 0;
}
int main()
{
        int i,t,ca=1;
        LL a,b;
        dp[1]=10;
        for(i=2;i<=17;i++)
        {
                if(i%2)
                        dp[i]=dp[i-1]*10;
                else
                        dp[i]=num[i/2];
        }
        cin>>t;
        while(t--)
        {
                cin>>a>>b;
                if(a>b)
                        swap(a,b);
                if(b<10)
                        b++;
                else
                {
                        putin(b);
                        b=solve();
                }
                if(a>10)
                {
                        putin(a-1);
                        a=solve();
                }
                cout<<"Case "<<ca++<<": "<<b-a<<endl;
        }
}


看了网上大触的做法,感觉我这个比起来要繁琐很多,但是比较容易想明白,偏低思考的做法Orz。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值