【题解】Luogu P4121 [CQOI2016]手机号码 数位DP

题目传送门

Solution

这里我采用记忆化搜索的形式实现有哪个大佬可以教教我递推板的数位dp啊

搜索的过程中记录是否曾出现8,是否曾出现4,是否曾有连续3个相同数字,搜到底返回就可以了

其实没有太多好写的,数位DP很多都是套模板

那还写来干嘛?

这道题

从$1e10$开始算!

从$1e10$开始算!

从$1e10$开始算!

这就意味着我们需要特殊处理最高位,而不是像普通的数位DP那样直接把最高位也丢进搜索里搜。

惨痛的70分教训大概只有我是这么蠢了嘤嘤嘤

Code

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#define maxb 15
using namespace std;
typedef long long ll;

ll l,r;
ll dp[maxb][15][15][2][2][2];
ll b[maxb],len;

ll dfs(ll pos,ll lst,ll llst,bool rep,bool four,bool eight,bool limit)
{
    if(!pos)
        return ((!eight)||(!four))&&rep;
    if(~dp[pos][lst][llst][rep][four][eight] && !limit)
        return dp[pos][lst][llst][rep][four][eight];
    ll re=0;
    for(register ll i=0;i<=(limit?b[pos]:9);++i)
        re+=dfs(pos-1,i,lst,rep||((i==lst)&&(lst==llst)),four||(i==4),eight||(i==8),limit&&(i>=b[pos]));
    if(!limit)
        dp[pos][lst][llst][rep][four][eight]=re;
    return re;
}

ll Work(ll num)
{
    if(num<1e10)
        return 0;
    memset(dp,-1,sizeof(dp));
    memset(b,0,sizeof(b));
    len=0;
    while(num)
    {
        b[++len]=num%10;
        num/=10;
    }
    ll re=0;
    for(register ll i=1;i<=b[len];++i)
        re+=dfs(len-1,i,10,0,i==4,i==8,i==b[len]);
    return re;
}

int main()
{
    scanf("%lld%lld",&l,&r);
    printf("%lld",Work(r)-Work(l-1));
    return 0;
}

懒得分整形长整了直接全部ll

原文地址:https://www.cnblogs.com/lizbaka/p/10260928.html

时间: 2024-10-06 23:50:47

【题解】Luogu P4121 [CQOI2016]手机号码 数位DP的相关文章

【题解】Luogu P4121 [CQOI2016]手机号码

Solution 这里我采用记忆化搜索的形式实现有哪个大佬可以教教我递推板的数位dp啊 搜索的过程中记录是否曾出现8,是否曾出现4,是否曾有连续3个相同数字,搜到底返回就可以了 其实没有太多好写的,数位DP很多都是套模板 那还写来干嘛? 这道题 从\(1e10\)开始算! 从\(1e10\)开始算! 从\(1e10\)开始算! 这就意味着我们需要特殊处理最高位,而不是像普通的数位DP那样直接把最高位也丢进搜索里搜. 惨痛的70分教训大概只有我是这么蠢了嘤嘤嘤 Code #include <cst

【luogu4124】【bzoj4521】 [CQOI2016]手机号码 [数位dp]

P4124 [CQOI2016]手机号码 4521 这道题要注意卡上下界 我错了 写dfs版的更好考虑状态 写纯方程转移那个细节把我想瓜了 1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<cstring> 5 #include<cmath> 6 #include<stack> 7 #include<algorithm> 8 using

4521: [Cqoi2016]手机号码|数位DP

数据范围这么小..感觉暴力可过啊.. DP也是随便设计状态 F[i][j][k][s][l] 表示前i位,最后一位是j 最后一位连续出现k次(如果k已经等于3那么就一直不变)s表示4,8的出现状态 l表示前缀是否和原数的前缀相同 转移就是枚举下一位转移,也很简单.. #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio>

BZOJ 4521 CQOI 2016 手机号码 数位DP

4521: [Cqoi2016]手机号码 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 539  Solved: 325[Submit][Status][Discuss] Description 人们选择手机号码时都希望号码好记.吉利.比如号码中含有几位相邻的相同数字.不含谐音不 吉利的数字等.手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号 码单独出售.为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码

【BZOJ-4521】手机号码 数位DP

4521: [Cqoi2016]手机号码 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 303  Solved: 194[Submit][Status][Discuss] Description 人们选择手机号码时都希望号码好记.吉利.比如号码中含有几位相邻的相同数字.不含谐音不吉利的数字等.手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号码单独出售.为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数量

HDU 3709 数位dp

Balanced Number Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 5276    Accepted Submission(s): 2523 Problem Description A balanced number is a non-negative integer that can be balanced if a pi

51NOD 1623 完美消除 数位DP

题目描述: 定义数的消除操作为选定[L,R,x],如果数的第L到第R位上的数字都大于等于x,并且这些数都相等,那么该操作是合法的(从低位到高位编号,个位是第一位,百位是第二位……),然后将这些位数上的数减x:否则就是不合法的,不能进行操作.对一个数操作最少的次数使得这个数变成0,这个操作次数称为该数的最小操作数.如:1232的最小操作数为3,一个合法解是[2,2,1],[1,3,2],[4,4,1]. 求L~R中最小操作数为k的数的个数. 例如:132,需要操作3次才能变为0.而131131 =

codeforces 215E 数位DP

题意:一个数的二进制表示如果是一个周期数那么它就是需要的,问[l,r]中有多少个好的数 题解:明显很像数位DP,枚举第一周期的长度,根据第一周期的数值大小来确定有多少种方案,注意首位不能为0.然后就是要注意去重问题,因为对于第一周期长度为k算到的数字,长度为k可以整除的数时必定也算过一遍,减一下就好了,根据这个去重 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<stri

bzoj 1026 [SCOI2009]windy数 数位dp

1026: [SCOI2009]windy数 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1026 Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? Input 包含两个整数,A B. Output 一个整数.