HDU 2089 不要62(数位dp)

题意:给定一个区间[n, m],求这个区间当中不含62和4的个数。例如62315,88914就是不符合条件的。

数位dp第一题,dp[i][j]表示以 j 开头的 i 位数满足条件的个数,先要预处理出来所有的情况,

下面是预处理的核心。其中k表示j后面的那一位。max_len是题目中给的n的最大位数,这里是7,第二层for是枚举第max_len - i位的值。

for (int i = 1; i <= max_len; i++)
{
    for (int j = 0; j <= 9; j++)
    {
        for (int k = 0; k <= 9; k++)
        {
            if (j != 4 && !(j == 6 && k == 2))
                dp[i][j] += dp[i - 1][k];
         }
    }
}预处理这些之后,可以对于输入的数字进行处理,还要用到一个函数,就是统计从0~n符合条件的数是多少。注意这是闭区间【0,n】。对于每一个数,统计每一位比他小的,从左到右统计,例如547这个数,首先从左边开始统计百位小于5符合条件的有dp[3][0], dp[3][1], dp[3][2], dp[3][3], 意思就是百位数取0的时候后面有多少,取1的时候有多少...知道取到比这个数小1,为什么没有dp[3][4],因为4不符合题目中的条件。同样,继续循环到十位,比4小的就是dp[2][3], dp[2][2], dp[2][1], dp[2][0], 继续往下走就是比7小的,dp[1][0], dp[1][1]...dp[1][6].
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>

using namespace std;
typedef long long ll;
const int maxn = 11;
int dp[maxn][maxn];
const int max_len = 7;
void init()
{
    dp[0][0] = 1;
    for (int i = 1; i <= max_len; i++)
    {
        for (int j = 0; j <= 9; j++)
        {
            for (int k = 0; k <= 9; k++)
            {
                if (j != 4 && !(j == 6 && k == 2))
                    dp[i][j] += dp[i - 1][k];
            }
        }
    }
}
int digit[maxn];
bool check(int n)
{
    for (int i = n; i > 0; i--)
        if (digit[i] == 4 || (digit[i] == 2 && digit[i + 1] == 6))
            return false;
    return true;
}
int get_cnt(int n)
{
    memset(digit, 0, sizeof(digit));
    int cnt = 0;
    int ans = 0;
    while (n)
    {
        digit[++cnt] = n % 10;
        n /= 10;
    }
    if (check(cnt))
        ans++;
    for (int i = cnt; i > 0; i--)
    {
        for (int j = 0; j < digit[i]; j++)
        {
            if (j != 4 && !(j == 2 && digit[i + 1] == 6))
                ans += dp[i][j];
        }
        if (digit[i] == 4 || (digit[i] == 2 && digit[i + 1] == 6))
            break;
    }
    return ans;
}
int main()
{
    init();
    int n, m;
    while (~scanf("%d %d", &n, &m) && (n + m))
    {
        int ans = get_cnt(m) - get_cnt(n - 1);
        printf("%d\n", ans);
    }
    return 0;
}

还有一个技巧就是get_cnt(m)得到的是区间【0,m】之间的个数,所以【n, m】就是get_cnt(m) - get_cnt(n - 1),不过这里得处理一下函数判断当前这个数是不是符合条件。后来我看网上都直接写get_cnt(m+1) - get_cnt(n), 后来想想其实这样比我的写法要好一点,因为这样就可以不用判断当前这个值是否满足条件了。

时间: 2024-10-12 17:29:34

HDU 2089 不要62(数位dp)的相关文章

[ACM] hdu 2089 不要62(数位Dp)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 19043    Accepted Submission(s): 6442 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就

HDU 2089 不要62(数位DP,三种姿势)

HDU 2089 不要62(数位DP,三种姿势) ACM 题目地址:HDU 2089 题意: 中文题意,不解释. 分析: 100w的数据,暴力打表能过 先初始化dp数组,表示前i位的三种情况,再进行推算 直接dfs,一遍搜一变记录,可能有不饥渴的全部算和饥渴的部分算情况,记录只能记录全部算(推荐看∑大的详细题解Orz) 代码: 1. 暴力 (以前写的) /* * Author: illuz <iilluzen[at]gmail.com> * File: 2089_bf.cpp * Create

HDU 2089 不要62(数位dp&amp;记忆化搜索)

题目链接:[kuangbin带你飞]专题十五 数位DP C - 不要62 题意 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众. 不吉利的数字为所有含有4或62的号码.例如: 62315 73418 88914 都属于不吉利号码.但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列. 你的任务是,对于每次给

HDU 2089 不要62 (数位dp水题)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 32358    Accepted Submission(s): 11514 题目链接 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样

HDU 2089 不要62 数位DP入门

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

HDU 2089 不要62 数位dp(入门

题目链接:点击打开链接 中文题. 问区间内有多少个合法数字(一个数是合法数字须满足1.不含4 ,2.每个6后面都不是2 dp[i][0]表示长度为i的数字中,前一位不为6时的合法个数, dp[i][1]表示长度为i的数字中前一位是6的合法个数. #include <cstdio> #include <algorithm> #include <cstring> #include <iostream> using namespace std; typedef l

HDU 2089 不要62 (数位DP)

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

hud 2089 不要62 (数位dp)

#include<stdio.h> #include<string.h> #include<math.h> #define max 10 int dp[max][3]; int number[max]; //dp[i][0] 前i位数中不符合要求的总个数 //dp[i][1] 前i位数中最高位是2的个数 //dp[i][2] 前i位数中存在含4和有连续62的个数 void init() { memset(dp,0,sizeof(dp)); dp[0][0]=1; for

HDU 3555 Bomb ,HDU 2089 深刻学习数位dp (各种方法乱用)

数位dp是与数位有关的区间统计 参考: 点击打开链接 思想是将数字拆分,dp[i][j] 长度为i的数字有多少个满足j条件的,从000~999 统计时,计当前数字为x,则其后面数字的变化的倍数是0~x-1 后面接000~999这样刚好统计不到这个数字n本身. eg: 对于一个数,若其首位已经比询问上界小,则剩余位没有任何限制.此时如果能直接处理这一情况,则问题距离解决又会迈出一大步. 例如,在十进制下,计算[10000,54321]内的数字和,我们可以将其分解为: [10000,19999],[