题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4521

题意概述:给出一个区间[L,R],统计区间中满足:1、4,8不同时出现;2、至少有3个相邻的相同数字 的数字个数。10^10<=L<R<10^11.

实际上要想个状态方程和转移很好想,只是细节和答案就有点。。。。

简单来说,设f(i,x,y,0/1/2,0/1)表示第i位上的数是x,第i-1位上的数是y,4,8没有出现过 / 4出现过 / 8出现过,有/无三个相邻的相同数字的数字数量。

转移的时候f(1,x,y,0/1/2,0/1)可以直接暴力初始化,然后转移过程中对方程后两个位置上的状态讨论即可(分为之前就是这样和之前不是这样但是这一步变成了这样两种)。

计算答案的时候从高到低考虑,同时注意当前确定下来的数里面4,8出现的情况以及有无相邻的三个数字,以加上限制或者增加更新范围。

最后说一点建议L那个位置特判一下否则很惨。。。。

然后循环的时候上界不要写错了,不要脑子不知道发生了什么把10写成了9之类的耗掉了1h,不要问我怎么知道的!!!!!

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #include<set>
 9 #include<map>
10 #include<vector>
11 #include<cctype>
12 using namespace std;
13 typedef long long LL;
14
15 LL L,R,f[13][10][10][3][2];
16
17 void dp()
18 {
19     for(int x=0;x<10;x++)
20     for(int y=0;y<10;y++){
21         f[1][x][y][0][0]=x!=4&&x!=8&&y!=4&&y!=8?1:0;
22         f[1][x][y][1][0]=(x==4||y==4)&&x!=8&&y!=8?1:0;
23         f[1][x][y][2][0]=(x==8||y==8)&&x!=4&&y!=4?1:0;
24     }
25     for(int i=2;i<=10;i++)
26     for(int x=0;x<10;x++){
27         for(int y=0;y<10;y++)
28         for(int z=0;z<10;z++){
29             if(x!=4&&x!=8&&(x!=y||x!=z)) f[i][x][y][0][0]+=f[i-1][y][z][0][0];
30             if(x!=8&&(x!=y||x!=z)) f[i][x][y][1][0]+=f[i-1][y][z][1][0];
31             if(x==4&&(x!=y||x!=z)) f[i][x][y][1][0]+=f[i-1][y][z][0][0];
32             if(x!=4&&(x!=y||x!=z)) f[i][x][y][2][0]+=f[i-1][y][z][2][0];
33             if(x==8&&(x!=y||x!=z)) f[i][x][y][2][0]+=f[i-1][y][z][0][0];
34             if(x!=4&&x!=8) f[i][x][y][0][1]+=f[i-1][y][z][0][1];
35             if(x!=8) f[i][x][y][1][1]+=f[i-1][y][z][1][1];
36             if(x==4) f[i][x][y][1][1]+=f[i-1][y][z][0][1];
37             if(x!=4) f[i][x][y][2][1]+=f[i-1][y][z][2][1];
38             if(x==8) f[i][x][y][2][1]+=f[i-1][y][z][0][1];
39         }
40         if(x!=4&&x!=8) f[i][x][x][0][1]+=f[i-1][x][x][0][0];
41         if(x!=8) f[i][x][x][1][1]+=f[i-1][x][x][1][0];
42         if(x!=4) f[i][x][x][2][1]+=f[i-1][x][x][2][0];
43     }
44 }
45 LL calc(LL A)
46 {
47     int n[15]={0},cnt=0;
48     n[cnt++]=A%10,A/=10;
49     while(A) n[cnt++]=A%10,A/=10;
50     LL re=0;
51     for(int x=1;x<n[10];x++)
52     for(int y=0;y<10;y++)
53         re+=f[10][x][y][0][1]+f[10][x][y][1][1]+f[10][x][y][2][1];
54     int x=n[10];
55     int ok=0,p4=x==4,p8=x==8;
56     for(int i=10;i>=1;i--){
57         for(int y=0;y<n[i-1]+(i==1);y++){
58             if(y==4&&p8||y==8&&p4) continue;
59             re+=f[i][x][y][0][1];
60             if(!p8) re+=f[i][x][y][1][1];
61             if(!p4) re+=f[i][x][y][2][1];
62             if(ok||x==y&&x==n[i+1]){
63                 re+=f[i][x][y][0][0];
64                 if(!p8) re+=f[i][x][y][1][0];
65                 if(!p4) re+=f[i][x][y][2][0];
66             }
67         }
68         x=n[i-1],p4|=(x==4),p8|=(x==8);
69         if(n[i-1]==n[i]&&n[i]==n[i+1]) ok=1;
70         if(p4&&p8) break;
71     }
72     return re;
73 }
74 int check(LL x)
75 {
76     int n[15]={0},cnt=0,p4=0,p8=0,ok=0;
77     n[cnt++]=x%10,x/=10;
78     while(x) n[cnt++]=x%10,x/=10;
79     for(int i=0;i<cnt;i++){
80         p4|=n[i]==4,p8|=n[i]==8;
81         if(p4&&p8) return 0;
82         if(i>1&&n[i]==n[i-1]&&n[i]==n[i-2]) ok=1;
83     }
84     return ok;
85 }
86 int main()
87 {
88     cin>>L>>R;
89     dp();
90     cout<<calc(R)-calc(L)+check(L)<<'\n';
91     return 0;
92 }

转载于:https://www.cnblogs.com/KKKorange/p/8562653.html

BZOJ 4521 CQOI2016 手机号码 数位dp相关推荐

  1. [CQOI2016]手机号码 数位DP

    [CQOI2016]手机号码 用来数位DP入门,数位DP把当前是否需要限制取数范围(是否正在贴着临界值跑,即下面的limited)和一切需要满足的条件全部塞进记忆化搜索参数里面就好了,具体情况转移便好 ...

  2. bzoj 4521 [ Cqoi 2016 ] 手机号码 —— 数位DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4521 数位DP,记录好多维状态: 写了半天,复杂得写不下去了,于是参考一下TJ... 练习简 ...

  3. Bzoj 3652: 大新闻(数位dp)

    以下内容来自ShallWe's Blog 题目 3652: 大新闻 Description Input Output \(1<=N<=10^18\) 解题报告 显然是一道数位dp的题目,观 ...

  4. BZOJ 1026 windy数 (数位DP)

    题意 区间[A,B]上,总共有多少个不含前导零且相邻两个数字之差至少为2的正整数? 思路 状态设计非常简单,只需要pos.limit和一个前驱数pre就可以了,每次枚举当前位时判断是否与上一位相差2即 ...

  5. 【洛谷P4124】[CQOI2016]手机号码

    手机号码 数位DP模板题 记忆化搜索: #include<iostream> #include<cstring> #include<cstdio> using na ...

  6. [SOCI2005]最大子矩阵(DP) + [JXOI2018]守卫(DP) + [CQOI2016]手机号码(数位DP)[各种DP专练]

    DP专练博客 DP专练 T1:最大子矩阵 题目 题解 代码实现 T2:守卫 题目 题解 代码实现 T3:手机号码 题目 题解 代码实现 T1:最大子矩阵 题目 这里有一个n*m的矩阵,请你选出其中k个 ...

  7. [BZOJ4521][Cqoi2016]手机号码 (数位dp)

    题目描述 人们选择手机号码时都希望号码好记.吉利.比如号码中含有几位相邻的相同数字.不含谐音不吉利的数字等.手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号码单独出售.为了便于前 ...

  8. BZOJ 1799 [Ahoi2009] self 同类分布(数位DP)【BZOJ千题计划(quexin】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/1799(样例时限设置有问题,应该为 2 ...

  9. BZOJ 3329 Xorequ (数位DP、矩阵乘法)

    BZOJ 3329 Xorequ (数位DP.矩阵乘法) 手动博客搬家: 本文发表于20181105 23:18:54, 原地址https://blog.csdn.net/suncongbo/arti ...

最新文章

  1. php zblog 侧边栏样式_zblogphp版如何实现导航栏下拉框
  2. (面试)java基础-String一些特性
  3. html研究中心,seo研究中心 教程:认识HTML、css的重要性-专业SEO技
  4. 复习--3--对于第三堂课的总结--将两个页面相互用超链接链接到一起
  5. Android调试秘钥证书指纹获取方式
  6. js中var、let、const区别
  7. 业务逻辑 : forex mlm
  8. Oracle的Net Configuration Assistant 配置
  9. PHP之常用设计模式
  10. [转载] python中append函数的用法
  11. pivot position_PIVOT用法详解
  12. 串口波形显示软件SerialChart的使用
  13. 面试官:聊聊二维码扫码登录的原理
  14. win10共享计算机时用户名和密码错误,win10系统共享文件密码错误的解决方法
  15. 【FACT】函数使用技巧
  16. 结构光三维重建(二)线结构光三维重建
  17. 瘟神的尾行 -- Rootkit技术发展史 (转载)
  18. 图解Word2vec
  19. Android设备与外接U盘实现数据读取操作
  20. 玩一玩Spring容器(可视化笔记02)

热门文章

  1. phpBB安装环境配置
  2. [PCB]PCB设计尾声-焊盘泪滴与铺铜设计的作用与具体操作
  3. Flutter 倒计时功能
  4. R语言计算31省份(除港澳台地区)省会城市的球面距离代码
  5. 关于当代宜兴方言若干问题的讨论(3)_拔剑-浆糊的传说_新浪博客
  6. python模拟春节集五福_用Python分析支付宝红包和2018年集五福活动,你准备好了吗?...
  7. 艾司博讯:拼多多怎样算延迟发货?
  8. webpack2--tidying up
  9. 抖音python广告用的什么音乐_抖音上那些魔性洗脑神曲音乐,我用Python教你一次性下载...
  10. Linux之RPM包的安装、升级与卸载命令