hdu 6148 Valley Numer (数位dp)

Problem Description

众所周知,度度熊非常喜欢数字。

它最近发明了一种新的数字:Valley Number,像山谷一样的数字。
当一个数字,从左到右依次看过去数字没有出现先递增接着递减的“山峰”现象,就被称作 Valley Number。它可以递增,也可以递减,还可以先递减再递增。在递增或递减的过程中可以出现相等的情况。
比如,1,10,12,212,32122都是 Valley Number。
121,12331,21212则不是。
度度熊想知道不大于N的Valley Number数有多少。
注意,前导0是不合法的。

Input

第一行为T,表示输入数据组数。
每组数据包含一个数N。
● 1≤T≤200
● 1≤length(N)≤100

Output

对每组数据输出不大于N的Valley Number个数,结果对 1 000 000 007 取模。

Sample Input

3

3

14

120

Sample Output

3

14

119

题意:让你统计小于n的满足各个数位上不会出现先上升再下降的数字的个数

一道基本的数位dp

代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 110;
 5 const ll mod = 1e9+7;
 6 char s[maxn];
 7 int dig[maxn];
 8 ll dp[110][10][2];
 9 ll dfs (int pos,int now,int up,int limit,int lead)//pos代表当前位 now代表上一位的数字 up=1表示到该位是上升状态
10                                                   //limit=1表示前几位贴着n的上界 lead=1表示当前状态有前导零
11 {
12     if (pos<0){         //如果dp到了最低位
13         if (lead) return 0; //如果当前结果是含有前导零的不计数
14         else return 1;  //否则计数
15     }
16     if (!limit&&!lead&&dp[pos][now][up]!=-1)    //如果当前的dp状态没有到达给的数的上界
17                                                 //而且,当前状态没有前导零而且之前计算过
18         return dp[pos][now][up];                //记忆化搜索直接返回
19     ll ans = 0;
20     int top;    //当前位能达到的最大值
21     if (limit) top = dig[pos];  //如果之前几位都达到了给的n的对应位的上限,此时这一位最大值就是n的pos位
22     else top = 9;               //如果前面几位没有贴着n的上界,那么这一位不管整个数怎么取都不会大于n,自然这一位最大值为9
23     for (int i=0;i<=top;++i){   //
24         if (up&&i<now) continue;    //如果之前的up为上升状态而这一位比上一位小不满足题意直接过掉
25         int nxtup;  //下一步up的状态
26         if (up||((i>now)&&(!lead))) //下一步是上升状态有两种情况 1.前几位已经是上升的了
27                                     //注意到这里已经保证如果up==1,那么此时i>=now
28                                     //2.这一位比上一位大而且上一位还不是0(前导零,比如002这样是不算上升的)
29         nxtup=1;                    //满足上面2个条件的任意一个的话下一步就是上升状态的
30         else nxtup=0;//否则下一步上升up为0
31         int nxtlead;    //下一步前导零的状态
32         if ((i==0)&&lead) nxtlead = 1;//当且仅当前几位有前导零而且这一位i还是0,下一步还是有前导零的
33         else nxtlead = 0;   //否则下一位就没有前导零
34         int nxtlimit;   //下一步上界的状态
35         if (limit&&i==dig[pos]) nxtlimit = 1;//当且仅当前几位一直贴着n的上界而且这一位还是贴着n的上界,此时下一步状态还是贴着上界
36         else nxtlimit = 0;//否则下一步就不贴着n的上界了
37         (ans+=(dfs(pos-1,i,nxtup,nxtlimit,nxtlead)))%=mod;//向下dp一位
38     }
39     if (!limit&&!lead)  //如果当前没到达边界而且没有前导零,这样的是有资格存进dp数组的
40                         //因为dp[pos][now][up]存的是到pos位,当前数字为now,上升状态为up,没有到达上界而且没有前导零的数目
41         return dp[pos][now][up]=ans;
42     return ans;//如果没有资格直接返回答案计数就行了
43 }
44 int main()
45 {
46     int T;
47     //freopen("de.txt","r",stdin);
48     scanf("%d",&T);
49     memset(dp,-1,sizeof dp);
50     while (T--){
51         scanf("%s",s);
52         int len = strlen(s);
53         for (int i=0;i<len;++i)
54             dig[i]=s[i]-‘0‘;
55         reverse(dig,dig+len);
56         cout<<dfs(len-1,0,0,1,1)<<endl;
57     }
58     return 0;
59 }
时间: 2024-10-23 20:14:35

hdu 6148 Valley Numer (数位dp)的相关文章

2017&quot;百度之星&quot;程序设计大赛 - 复赛1005&amp;&amp;HDU 6148 Valley Numer【数位dp】

Valley Numer Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 311    Accepted Submission(s): 165 Problem Description 众所周知,度度熊非常喜欢数字. 它最近发明了一种新的数字:Valley Number,像山谷一样的数字. 当一个数字,从左到右依次看过去数字没有出现先递增接

HDU 6148 Valley Numer(数位DP)

1 #include <iostream> 2 #include <queue> 3 #include <stack> 4 #include <cstdio> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <bitset> 9 #include <algorithm> 10 #include <cmath>

hdu 3555 Bomb(数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意:就是给你一个数n,判断从0到n有多少个数含有数字49...... 是不是觉得跟hdu2089很相似呀... 思路:跟hdu2089一样的,注意给出的数比较大,所以这儿用__int64  .... code: #include<cstdio> #include<iostream> #include<cstring> #include<algorithm&

[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 - 3555 Bomb (数位DP)

题意:求1-n里有多少人包含"49"的数字 思路:数位DP,分三种情况:到第i位没有49的情况,到第i位没有49且最高位是9的情况,到第i位有49的情况,将三种情况都考虑进去就是了 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; long long dp[30][3], n; int arr

HDU 4518 ac自动机+数位dp

吉哥系列故事--最终数 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 304    Accepted Submission(s): 102 Problem Description 在2012年腾讯编程马拉松比赛中,吉哥解决了一道关于斐波那契的题目,这让他非常高兴,也更加燃起了它对数学特别是斐波那契数的热爱.现在,它又在思考一个关于斐波那契

HDU Word Index (数位DP)

题意:给你字符串,算出它的数值: a -> 1 b -> 2 . . z -> 26 ab -> 27 ac -> 28 . . az -> 51 bc -> 52 . . vwxyz -> 83681 字母要求递增. #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #incl

HDU 4722 Good Numbers (数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4722 思路:数位dp,dp[i][j]表示到第i位,数字和%10为j,然后进行dp,注意完全匹配的情况是要+1,而其他情况是从0 到 9 都要考虑 代码: #include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> using namespace std; int