【hdu6148】Valley Numer【数位dp模板题】

题意

  对于每组数据给出一个整数n(length(n)<=100),找出不大于n的数字中有多少是Valley Numer。对于Valley的定义是它每一位的数字要么是递增,要么是递减,要么是先递减后递增

分析

  选拔赛的时候遇到了数位dp,以前只是听说但是没学过今天就拿出来一天的时间学了一下数位DP。

  我们发现单调递减变为单调递增合法,单调递增变为递减不合法,所以通过增减判断最多只有一个拐点。那么我们在dp的时候状态只要记录当前是递增还是递减就可以了。

  我们用dp[p][pre][state]来进行记忆化。p代表的是位数,pre代表的是上一位的值,state代表是递减还是递增。

  这个算是数位dp很板子的一个题目,但是我一开始一直wa,感觉自己考虑的很对,然后最后看题解发现自己没有考虑前导0.

  我们发现,当存在前导0的时候,相当于从这里新开一个数字,那么当前是递增还是递减就不确定了,没法根据前面的0来判断,所以当存在前导0的时候步可以记忆化否则会因为dp数组的冲突而导致答案错误。

  

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 typedef long long LL;
 8 const int mod=1000000007;
 9 const int maxn=100+10;
10 int n,a[maxn],pos,T;
11 char s[maxn];
12 LL dp[maxn][10][2];//0 上升 1 下降
13 LL dfs(int p,int pre,int state,int lead,int limit){
14     if(p==0){
15         if(lead)
16             return 0;
17         return 1;
18     }
19     if(!limit&&dp[p][pre][state]!=-1&&!lead)
20         return dp[p][pre][state];
21     int up=limit?a[p]:9;
22     LL res=0;
23     for(int i=up;i>=0;i--){
24         if(state==0&&i<pre)
25             continue;
26         int st;
27         if(i==pre)st=state;
28         else if(i<pre)st=1;
29         else st=0;
30         if(lead)st=1;
31         res=(res+dfs(p-1,i,st,lead&&i==0,limit&&i==a[p]))%mod;
32     }
33     if(!limit&&!lead)
34         dp[p][pre][state]=res;
35     return res;
36 }
37 LL solve(){
38     pos=0;
39     for(int i=n-1;i>=0;i--){
40         pos++;
41         a[pos]=s[i]-'0';
42     }
43     memset(dp,-1,sizeof(dp));
44     return dfs(pos,0,0,1,1);
45 }
46 int main(){
47     scanf("%d",&T);
48     for(int t=1;t<=T;t++){
49         scanf("%s",s);
50         n=strlen(s);
51         printf("%lld\n",solve()%mod);
52     }
53 return 0;
54 }
View Code

 

posted @ 2018-09-15 01:40  蒟蒻LQL  阅读(398)  评论(0编辑  收藏  举报