2019.5.1 DP专题训练 山峰数(hill)
数位dp,感觉理解更深刻了一些
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e6+7; const int N=505; ll dp[N][N][2][2];//定义状态dp[长度][前一位][是否压上界][上升还是下降] int a[maxn]; int len; ll dfs(int lennow,int pre,int limit,int down){ if(lennow==len+1) return 1; if(dp[lennow][pre][limit][down]!=-1) return dp[lennow][pre][limit][down];//记忆化搜索的模板 ll ans=0; int maxx=limit?a[lennow]:9;//能够枚举的数,达到上限是前一个,否则就从0-9枚举 for(int i=0;i<=maxx;i++){ if(!down){//如果没有下降 if(i>=pre){//当前的数比前一个大 ,没有在下降 ans+=dfs(lennow+1,i,limit && i==maxx,0); } else{ ans+=dfs(lennow+1,i,limit && i==maxx,1);//已经在下降了,标记 } } else if(i<=pre){ ans+=dfs(lennow+1,i,limit && i==maxx,1);//一直在下降 } } return dp[lennow][pre][limit][down]=ans; } int T; char s[maxn]; int main() { freopen("hill.in","r",stdin); freopen("hill.out","w",stdout); scanf("%d",&T); while(T--){ scanf("%s",s); len=strlen(s); // printf("%d\n",len); for(int i=0;i<len;++i){ a[i+1]=s[i]-'0'; } // for(int i=1;i<=len;++i){ // printf("%d ",a[i]); // } // printf("\n"); bool down=false; bool hill=true; for(int i=2;i<=len;++i){//判断是否为山峰数 if(a[i]<a[i-1]) down=true; if(down&&a[i]>a[i-1]){ printf("-1\n"); hill=false; break; } } if(hill) { memset(dp,-1,sizeof(dp)); cout<<dfs(1,0,1,0)-1<<endl; } } return 0; }