HUD 2089 位数dp

/*
做的不多的位数dp
暴力的话 不知道多少组数据 会T
所以写dp 思路就和数学课本上那种“不超过xxx的x位偶数有几个”
这里可以类似的维护一个前缀和模样的东西(但又不同于前缀和)
状态:f[i][j] 表示以j开头的i位数符合条件的个数 (j可以是0)
然后可以已处理一下像是10000这种整的数 注意舍去不符合条件的 
然后对于一个像123456这样不整的数 就从该高位逐位找 
以此类推  
*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int st,en,ans,data[10],l,f[10][10];
void ready()
{
    f[0][0]=1;
    for(int i=1;i<=7;i++)//枚举位数 
      for(int j=0;j<=9;j++)//枚举第i为是什么 
        for(int k=0;k<=9;k++)//枚举第i-1为是什么 
          if((j==6&&k==2)||j==4||k==4)continue;//舍去 
          else f[i][j]+=f[i-1][k];
}
void get_data(int x)
{
    while(x>0)
      {
          data[++l]=x%10;
          x=x/10;
      }
}
int slove(int x)
{
    ans=0;l=0;
    memset(data,0,sizeof(data));
    get_data(x);//得到每一个数拆完是什么 
    for(int i=l;i>=1;i--)
      {
          for(int j=0;j<data[i];j++)//枚举第i位是什么 枚举到<data[i] 
            if((j==2&&data[i+1]==6)||j==4)continue;
            else ans+=f[i][j];
        if(data[i]==4||(data[i]==2&&data[i+1]==6))break;//往后找的一定包含这个4 或者62 就不用找了 
      }
    return ans;
}
int main()
{
    //freopen("cin.in","r",stdin);
    //freopen("test.out","w",stdout);
    ready();
    while(1)
      {
          scanf("%d%d",&st,&en);
          if(st==0&&en==0)break;    
        printf("%d\n",slove(en+1)-slove(st));
      }
    return 0;
}

 

posted @ 2016-05-16 18:15  一入OI深似海  阅读(226)  评论(0编辑  收藏  举报