【数位dp】山峰数

【数位dp】 山峰数

题目来源:5月1日第一次dp考试T2

>>>>题目

【题目描述】

山峰数是指数字排列中不存在山谷(先降后升)的数,例如0,5,13,12321都是山峰数,101,1110000111都不是山峰数。
现给出n个数,请依次判断它们是否为山峰数,如果不是,输出-1。如果是,求出比它小的数中有多少个山峰数。

【输入格式】

第一行一个数n,表示询问数目。
接下来n行,每一行一个数x,表示询问的数。

【输出格式】

输出有n行,x如果不是山峰数,输出-1。x如果是山峰数,则输出有多少个比它小的山峰数。

【输入样例】

5
10
55
101
1000
1234321

【输出样例】

10
55
-1
715
94708

【数据范围】

20% 数据满足x ≤ 1e6。
100% 数据满足n ≤ 10, x ≤ 1e60

 

>>>>代码

啊因为我不知道应该分析什么……就是dfs版的数位dp

直接看代码好啦

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll f[62][10][2][2];//f[i][j][k][p]:第i位上一个数是j,是否是上升期,是否压上界 的方案数 (其中是和否分别用1和0表示) 
int len,T,a[62];
char s[65];
ll dfs(int pos,int pre,int isdown,int lim)
{//   现在的位置  上一个数  是否是下降期  是否压上界 
    if(pos==len+1) return 1;//返回一种可行的方案数 
    if(f[pos][pre][isdown][lim]!=-1) return f[pos][pre][isdown][lim];//记忆化搜索 
    int up=lim?a[pos]:9;//上界 
    ll tmp=0;
    for(int i=0;i<=up;++i)
    {
        if(!isdown)
        {
            if(i>=pre) tmp+=dfs(pos+1,i,0,i==up&&lim);//一定要这一位和上一位都压上界,下一位才压上界 
            else tmp+=dfs(pos+1,i,1,i==up&&lim);//从这里开始下降 
        }
        else if(i<=pre) tmp+=dfs(pos+1,i,1,i==up&&lim);
    }
    return f[pos][pre][isdown][lim]=tmp;
}
int main()
{
    scanf("%d\n",&T);
    while(T--)
    {
        scanf("%s",s+1);
        len=strlen(s+1);
        for(int i=1;i<=len;++i) a[i]=s[i]-'0';
        
        bool ishill=true,isdown=false;//ishill:是否是山峰数,isdown:是下降期 
        for(int i=2;i<=len;++i)
        {
            if(a[i]<a[i-1]) isdown=true;
            if(isdown&&a[i]>a[i-1])//判断是否是山峰数 
            {
                ishill=false; 
                break;
            }
        }
        if(!ishill) printf("-1\n");
        else 
        {
            memset(f,-1,sizeof(f));
            printf("%I64d\n",dfs(1,0,0,1)-1);//因为要求的是比它小的山峰数,所以要减一 
        }
    }
    return 0;
} 
/*
5
10
55
101
1000
1234321

->
10
55
-1
715
94708
*/

完结撒花✿✿ヽ(°▽°)ノ✿!!!

posted @ 2019-05-10 16:35  P小友P  阅读(566)  评论(0编辑  收藏  举报