1. 程式人生 > >Palindromic Numbers(數位dp)

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。