数位dp

板题 hdu2089
题目意思,输出某个给定区间(给定左和右)区间中满足一下条件的数,不含数字4 不含连续的62,(分开的6 和 2 是允许的),输出答案。

  • 直接数字打表可以解
  • 利用itoa打表也可以
  • 利用数位dp

利用数位dp解法
1、利用前缀和,注意最后输出的时候是r-(l-1),不是r-l,这样没有排除左端点的数
2、分别计算两个端点前面满足条件的数的个数
3、计算的时候利用dfs碰到不合法的数就不往下搜,合法的话就往下搜,搜的越深位数越小,直到最后的那一层是个位了
4、注意最后一层的遍历区间范围的问题,最后一层可能会碰到不能遍历到9 ,必然就会超过范围,于是在最后一位就用一个判断,如果是最后一位的话遍历范围就设置为当前这个数,不是最后一位统一都设成9,即由0遍历到9。

//
//  main.cpp
//  数位dp_模板_m
//
//  Created by 陈冉飞 on 2019/8/6.
//  Copyright © 2019 陈冉飞. All rights reserved.
//

#include <iostream>
#include <cstring>
using namespace std;
#define cl(a,b) memset(a,b,sizeof(a))
typedef long long ll;

int digit[105];
int dp[10][2];

int dfs(int len,bool is_six, bool limit){
    if (len == 0) {
        return 1;
    }
    if (!limit && dp[len][is_six]) {
        return dp[len][is_six];
    }
    
    int cnt = 0;
    //不是最后一位的话就用9,然后从1到9,是最后一位的话就用最后一位的那个数,即digit[len]
    int maxx = (limit ? digit[len]:9);
    for (int i = 0; i <= maxx; i++) {
        //两种情况
        if (i == 4 || (i == 2 && is_six)) continue;
        //如果当前位置为6,则等于这个位的状态往前传1
        if (i == 6) cnt += dfs(len-1, true, limit&&(i == maxx));
        else cnt += dfs(len - 1,false, limit&&(i == maxx));
    }
    return limit?cnt:dp[len][is_six] = cnt;
}

int trans(int n){
    //初始化
    int len = 0;
    cl(digit,0);
    cl(dp, 0);
    while (n>0) {
        digit[++len] = n%10;
        n/=10;
    }
    return dfs(len, false,true);
}

int main(int argc, const char * argv[]) {
//    cout<<trans(14)<<endl;
    int l,r;
    while (~scanf("%d%d",&l,&r)&&l != 0) {
//        cout<<trans(r)-trans(l)<<endl;//不是r-l
        cout<<trans(r)-trans(l-1)<<endl;
    }
    return 0;
}

数字itoa 然后遍历字串然后再看,(0<n≤m<1000000) 然后每次用itoa转换成string,然后就用string中判断是否字串的函数

//
//  main.cpp
//  hdu2089_itoa_打表
//
//  Created by 陈冉飞 on 2019/8/6.
//  Copyright © 2019 陈冉飞. All rights reserved.
//

#include <iostream>
#include <stdio.h>
#include <string>
#include <cstring>
#include <stdlib.h>
using namespace std;
typedef long long ll;
int ans[1000050];

int main(int argc, const char * argv[]) {
//    ans[0] = 0;
//    int a = 271;
//    char temstr[1000050];
//    sprintf(temstr, "%d", a);
    char temstr[1000050] = {'2','7','1'};
//
//    if (strstr(temstr, "71") ==  NULL) {
//        cout<<"404"<<endl;
//    }else cout<<"yes"<<endl;
    ans[0] = 0;
    char temstr[1000050];
    for (int i = 1; i <= 1000000; i++) {
        sprintf(temstr, "%d",i);
        if (strstr(temstr,"4") == NULL &&strstr(temstr, "62") == NULL) {
            ans[i] = ans[i-1]+1;
        }else ans[i] = ans[i-1];
    }
//    for (int i = 0; i < 1000; i++) {
//        cout<<i<<"  "<<ans[i]<<endl;
//    }

    int l,r;
    while (~scanf("%d%d",&l,&r)&&l != 0) {
        cout<<ans[r]-ans[l-1]<<endl;
    }
//    for (int i = 1; i <= 1000; i++) {
//        sprintf(temstr, "%d", i);
//        //strstr只是char数组的功能
//        if (strstr(temstr, "4") == NULL && strstr(temstr ,"62" == NULL) {
//            ans
//        }
        cout<<temstr<<endl;
//    }
//
//    int i = 90;
//    temstr = to_string(i);
//    cout<<temstr<<endl;
    return 0;
}

由于xcode无论调用什么库函数也没法用itoa 所以最后查到了sprintf这个方法来吧int转换成char数组。注意判断子字串的strstr方法应用对象为char数组。

int main(int argc, const char * argv[]) {
    ans[0] = 0;
    char temstr[1000050];
    for (int i = 1; i <= 1000000; i++) {
        sprintf(temstr, "%d",i);
        if (strstr(temstr,"4") == NULL &&strstr(temstr, "62") == NULL) {
            ans[i] = ans[i-1]+1;
        }else ans[i] = ans[i-1];
    }
    int l,r;
    while (~scanf("%d%d",&l,&r)&&l != 0) {
        cout<<ans[r]-ans[l-1]<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值