light oj 1205(数位DP)

题目描述:

求给定区间中的回文数有多少个?

首先明确一点,如果一个数是回文数,那么给这个数两边加上相同的数,那么这个数还是回文数。

根据这点就可以进行递推了,p[start][end]=9*p[start+1][end-1](start位不为0)+p[start-1][end](start位为0);

在设计dfs的时候,由于回文数是对称的,所以只需要一个变量cur(cur>mid)就可以表示从cur到cur对称的位置的回文数的个数;

d[start][cur]表示从start位到cur位时,回文数的个数。

这句话隐含的意思是最高位为start,枚举到第cur位,由于是回文数,所以当cur>mid时,[cur,start]位确定,他们的对称位[1,start+1-cur]也就确定了,

还需枚举[cur,mid]这些位;当cur=mid时任意枚举,对回文数没有影响,当cur<mid时,由于是回文数,已经确定了,不需枚举。

再增加一维表示当前枚举的数字是不是回文数(([start,cur]位是否为回文数);

d[start][cur][state]表示从start位到cur位时,状态为state时回文数的个数。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define LL long long
LL n,m;
LL d[30][30][2];
int digit[30];
int num[30];
LL dfs(int start,int cur,int Zero,int state,bool fp)
{
    if(!cur)             
        return state;
    if(!fp && d[start][cur][state]!= -1) 
        return d[start][cur][state];
    LL ret = 0 ;int  fpmax = fp ? digit[cur] : 9;
    for(int i=0;i<=fpmax;i++)
    {
        if( (Zero &&(i==0)) )
            ret+=dfs(start-1,cur-1,Zero&&(i==0),state, fp&& i==fpmax);
        else
        {
            num[cur]=i;
            if( (start & 1)==1 )
            {
                int mid=((start+1)>>1);
                if(cur== mid)
                {
                    ret+=dfs(start,cur-1,0,state,fp&& i==fpmax);
                }
                else if(cur < mid )
                {
                    ret+=dfs(start,cur-1,0,state&& (num[mid*2-cur]==i),fp&& i==fpmax);
                }
                else if(cur>mid)
                {
                    ret+=dfs(start,cur-1,0,state,fp&& i==fpmax);
                }
            }
            else
            {
                int mid=(start>>1)+1;
                if(cur<mid)
                {
                   ret+=dfs(start,cur-1,0,state&& (num[start+1-cur]==i),fp&& i==fpmax);
                }
                else
                {
                   ret+=dfs(start,cur-1,0,state,fp&& i==fpmax);
                }
            }
        }
    }
    if(!fp)  //如果是前缀,当前得到的ret的值,就不能代表dp[len][state]的值
        d[start][cur][state] = ret;
    return ret;
}

LL f(LL n)
{
    int len = 0;
    if(n==-1)
        return 0;
    while(n)
    {
        digit[++len] = n % 10;
        n /= 10;
    }
    LL answer=dfs(len,len,1,1,true);
    return answer;
}
void init()
{
    memset(d,-1,sizeof(d));
}
int main()
{
    //  freopen("test.txt","r",stdin);
      int t;
      scanf("%d",&t);
      int Case=0;
      while(t--)
      {
        scanf("%lld%lld",&n,&m);
        init();
        if(n>m)
            swap(n,m);
        printf("Case %d: %lld\n",++Case,f(m)-f(n-1));
      }
      return 0;
}

 

posted on 2015-09-09 21:35  爱装逼的书呆子  阅读(306)  评论(0编辑  收藏  举报

导航