HDU2089 不要62(数位dp)

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf -0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
int dp[10][3];
//dp[i][0] 位数为i且不含不吉利数字
//dp[i][1]  位数为i且不含不吉利数字且第一位为2
//dp[i][2]   位数为i且含不吉利数字 

void init(){
    mem0(dp);       //dp数组置0
    dp[0][0]=1;
    for(int i=1;i<=6;i++){          //最多有6位 
        dp[i][0]=dp[i-1][0]*9-dp[i-1][1];           //前i-1为不含不吉利数字且排除4的情况-第i位为6且i-1位为2的情况
        dp[i][1]=dp[i-1][0];
        dp[i][2]=dp[i-1][2]*10+dp[i-1][0]+dp[i-1][1];  //dp[i-1][0]表示第一位为4,dp[i-1][1]第一位为6 
    //  cout<<dp[i][0]<<"PPPPP"<<dp[i][1]<<"PPPPP"<<dp[i][2]<<endl;
    } 
}

int solve(int n){
    int a[10];
    int len=0;
    int tmp=n;
    while(n){
        a[++len]=n%10;
        n/=10;
    }
    int ans=0,flag=0;
    a[len+1]=0;
    for(int i=len;i>=1;i--){
        ans+=dp[i-1][2]*a[i];               //则下面的情况dp[i-1]都是吉利数字 
        if(flag){
            ans+=dp[i-1][0]*a[i];           //如果存在不吉利树,任意处理 
        }
        if(!flag&&a[i]>4){                  //首位大于4,则出去首位可以放一的情况 
            ans+=dp[i-1][0];
        }
        if(!flag&&a[i+1]==6&&a[i]>2)        //前一位为6,则除去这一位第一个数放2的情况 
            ans+=dp[i][1];
        if(!flag&&a[i]>6)                   //除去下一位第一个数放1的情况 
            ans+=dp[i-1][1];
        if(a[i]==4||(a[i+1]==6&&a[i]==2))   
            flag=1;
    //  cout<<i<<"PPPPP"<<ans<<endl;
    }
    return tmp-ans;
} 


int main(){
    int n,m;
    init();
    while(scanf("%d%d",&n,&m)==2){
        if(n==0&&m==0)
            break;
        printf("%d\n",solve(m+1)-solve(n));  //如果直接为solve(m)的话未把m是否为不吉利数字考虑进去 
    }
    return 0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值