【数位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 ",&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 "); else { memset(f,-1,sizeof(f)); printf("%I64d ",dfs(1,0,0,1)-1);//因为要求的是比它小的山峰数,所以要减一 } } return 0; } /* 5 10 55 101 1000 1234321 -> 10 55 -1 715 94708 */
完结撒花✿✿ヽ(°▽°)ノ✿!!!