HDOJ3555
2016-05-09 19:24
232 查看
数位DP基础模板题
题目链接:HDOJ3555
先来膜拜一发我雨的题解:/article/2930165.html
题意很简单:判断区间【1,n】中有多少数字含有“49”这个子串
状态定义:
dp【i】【0】:前len位不含49,且高位不是4(不会影响下一个数字的枚举了,因为49的第一个字符是4,第len位可以任意选)
dp【i】【1】:前len位不含49,且高位是4(影响第len位的枚举,因为该位置是不是9,会影响到最后的答案)
dp【i】【2】:前len为已经有了49(之后也无所谓了,反正已经计数了)
贴上代码,来解释细节好了
题目链接:HDOJ3555
先来膜拜一发我雨的题解:/article/2930165.html
题意很简单:判断区间【1,n】中有多少数字含有“49”这个子串
状态定义:
dp【i】【0】:前len位不含49,且高位不是4(不会影响下一个数字的枚举了,因为49的第一个字符是4,第len位可以任意选)
dp【i】【1】:前len位不含49,且高位是4(影响第len位的枚举,因为该位置是不是9,会影响到最后的答案)
dp【i】【2】:前len为已经有了49(之后也无所谓了,反正已经计数了)
贴上代码,来解释细节好了
#include<map> #include<set> #include<math.h> #include<time.h> #include<iostream> #include<cstdio> #include<queue> #include<stack> #include<stdio.h> #include<cstring> #include<string.h> #include<algorithm> #include<cstdlib> using namespace std; #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define ll rt<<1 #define rr rt<<1|1 #define LL long long #define ULL unsigned long long #define maxn 1050 #define maxnum 1000050 #define eps 1e-6 #define input freopen("input.txt","r",stdin) #define output freopen("output.txt","w",stdout) /* dp[len][0]:前len位不含49且第len位不是4 dp[len][1]:前len位不含49且第len位为9(在加高位的4就可以符合题意了) dp[len][2]:前len位已有49 */ __int64 n; int digit[20]; __int64 dp[20][5]; __int64 dfs(int pos,int status,bool flag){ if (pos==0) return status==2; //pos==0已经枚举完了 //如果status为2,说明前len位已经有了49,就应该计数 //写成if (status==2) return 1; //else return 0;更好理解吧 if (flag&&dp[pos][status]!=-1) return dp[pos][status]; //dp不是-1是基本记忆化套路 //flag==true就是表示在高位的枚举中有某一位小于n的对应位了,所以这些数在【0,n】 区间内 //需要计数 int num=flag?9:digit[pos]; //如果flag=1,低位可以从0枚举到9 //否则只能枚举到n的相应位的数值 __int64 ans=0; for(int i=0;i<=num;i++){ if (status==2||(status==1&&i==9)) ans+=dfs(pos-1,2,flag||i<num); //如果前len位已经有了49 //或者原来高位是4(用status==1表示前一位是4) ,且该位枚举的9,即构成了49这个串 else if (i==4) ans+=dfs(pos-1,1,flag||i<num); //第len位枚举的是4,符合status=1 else ans+=dfs(pos-1,0,flag||i<num); //不是任何特殊情况,那就是status=0 } if (flag) dp[pos][status]=ans; //flag=1,说明可以计数 //否则,这个数会大于n,计数没有意义 return ans; } __int64 calc(__int64 n){ //标准格式 //将n分解成各个数位,从高到低 int pos=0; while(n){ digit[++pos]=n%10; n/=10; } return dfs(pos,0,0); } int main(){ //input; int T; scanf("%d",&T); while(T--){ scanf("%I64d",&n); memset(digit,0,sizeof(digit)); memset(dp,-1,sizeof(dp)); printf("%I64d\n",calc(n)); } return 0; }
相关文章推荐
- PAT B 1013. 数素数 (20)
- Java中的输入流
- 《小狗钱钱》
- 模板配置教程:Phpcms v9怎么更换模板
- Android Studio下jni应用
- JQuery入门
- 作为容器的div层设置宽度
- 实现图片的高效加载
- ny 108 士兵杀敌(一)-- 水(大家都是这么说的)利用线段树果断超时。。。
- 2、fragment的使用封装(下)
- 通用Adapter的尝试
- 第十、十一周阅读程序 继承和派生(4)
- android studio 之常见错误
- AsyncTask和Handler对比
- 前端框架学习
- 快速排序
- 第三方应用使用总结
- python命令行解析工具Argparse
- Reactor反应器模式
- Android四大组件的介绍