数位dp入门

作者: evilgiven | 来源:发表于2017-11-15 15:19 被阅读0次

之前稍微看过一点数位dp, 也没怎么练习, 现在鸽了这么久差不多全忘了.

今天一个小学弟跑来问我一个很水的题

多个输入, 每次一个正整数 n, 问 [1, n] 范围内有多少个回文数

题目没有明说 n 的范围, 我下意识就回顾了一下以前做这种题用的很傻逼的方法

预处理生成范围内所有的回文数, 排序再对每一个输入进行二分, 返回下标

这个做法真的太傻逼了= =
还好看过数位dp, 可以远离这种暴力流.
回顾一下数位dp入门题 hdu2089

不要62

Problem Description
杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。

Input

输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。

Output

对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。

Sample Input

1 100
0 0

Sample Output

80

当时照着模板打的代码

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

long long DDP[20][2];
int TN[20];

long long DigtialDFS(int pos, int pre, int sta, bool lead, bool limit){
    if(pos == -1) return 1;
    if(!lead && !limit && DDP[pos][sta] != -1) return DDP[pos][sta];
    int up = limit ? TN[pos] : 9;
    long long res = 0;
    for(int i = 0; i <= up; i++){
        if(i == 4 || (pre == 6 && i == 2)) continue;
        res += DigtialDFS(pos - 1, i, i == 6, lead && i == 0, limit && i == TN[pos]);
    }
    if(!limit) DDP[pos][sta] = res;
    return res;
}

long long DigtialDP(int x){
    int pos = 0;
    while(x) TN[pos++] = x % 10, x /= 10;
    return DigtialDFS(pos - 1, -1, 0, true, true);
}

int main()
{
    int n, m;

    memset(DDP, -1LL, sizeof(DDP));
    while(scanf("%d%d", &n, &m) != EOF && (n || m)) printf("%I64d\n", DigtialDP(m) - DigtialDP(n - 1));
    return 0;
}

一会儿再补注释和思路

#include <stdio.h>
#include <string.h>

int DDP[9][9][2];
int TN[20];

int DigtialDFS(int len, int pos, int sta, int limit){
    int i, up, res = 0;
    if(pos == -1) return sta;
    if(!limit && DDP[len][pos][sta] != -1) return DDP[len][pos][sta];
    up = limit ? TN[pos] : 9;
    for(i = 0; i <= up; i++){
        if(pos == len && i == 0) res += DigtialDFS(len - 1, pos - 1, sta, limit && i == up);
        else if(sta && pos < (len + 1) / 2) res += DigtialDFS(len, pos - 1, i == TN[len - pos], limit && i == up);
        else res += DigtialDFS(len, pos - 1, sta, limit && i == up);
    }
    if(!limit) DDP[len][pos][sta] = res;
    return res;
}

int DigtialDP(int x){
    int pos = 0;
    while(x) TN[pos++] = x % 10, x /= 10;
    return DigtialDFS(pos - 1, pos - 1, 1, 1);
}

int main()
{
    int n;

    memset(DDP, -1, sizeof(DDP));
    while(scanf("%d", &n) != EOF && n) printf("%d\n", DigtialDP(n) - 1);
    return 0;
}

相关文章

  • 数位dp入门

    之前稍微看过一点数位dp, 也没怎么练习, 现在鸽了这么久差不多全忘了. 今天一个小学弟跑来问我一个很水的题 多个...

  • 数位dp

    数位dp的入门题HDU - 2089 不要62题意:求区间[n,m]之间,不含有4和(连续的)62的数字个数。分析...

  • 数位dp

    数位dp是解决一类选择有约束的数字的个数的问题的解法,就是数一个区间有多少个满足题目条件的数字的个数,通常暴...

  • 数位DP

    1. 计数问题 原题链接[https://www.acwing.com/problem/content/340/]...

  • DP训练——数位DP

    数位DP BZOJ1026题意求到间,不含前导零且相邻两个数字之差至少为的正整数的个数。题解状态定义:表示当前处理...

  • 【进阶】数位DP详解

    今天,我向大家介绍一种特殊的DP类型——数位DP。数位DP这类题目一般不会出现在提高组及以下的比赛中(今后出现了当...

  • [数位dp] Pair

    输入正整数A,B,C,统计满足1≤x≤A,1≤y≤B且至少满足下列条件之一:①x and y > C②x xor ...

  • 数位DP 详解

    序 天堂在左,战士向右 引言 数位DP在竞赛中的出现几率极低,但是如果不会数位DP,一旦考到就只能暴力骗分。以下是...

  • 震惊!数位dp竟然还能有板子!!

    不要62(HDU - 2089)经典的数位dp的入门题。今天才知道原来这就可以做成一个板子。题意:给你一个l和一个...

  • 数位dp总结 之 从入门到模板

    转自http://blog.csdn.net/wust_zzwh/article/details/52100392...

网友评论

    本文标题:数位dp入门

    本文链接:https://www.haomeiwen.com/subject/ujgcvxtx.html