windy数
数位DP
用记忆化搜索来实现
dfs设五个参数 pos,len,pre,sta,limit;
pos为当前枚举到第几位,从高往低枚举。
pos | 为当前枚举到第几位,从高往低枚举。 |
len | 有没有前导零,0代表有,1代表没有 |
pre | 当前位的上一位 |
sta | 设的状态,这题有10个,为0~9分别代表当前位上是几 |
limit | 高位标记 |
设一个 f 数组
为位数为pos,上一位为pre,当前状态为sta时的答案
枚举每一位上的数字(0~9)
如果有高位标记,那么最多枚举到a[pos];
a[i]表示这个数的第i位是多少
那么很显然当abs(pre-i)<2就得跳过这个数
上代码
#include<cstdio> #include<cstring> #include<cmath> using namespace std; int f[100][10][100],a[100]; int dfs(int pos,int len,int sta,int pre,bool limit) { if (pos==0) return 1; if (!limit&&f[pos][sta][pre]!=-1) return f[pos][sta][pre]; int up=limit?a[pos]:9;//判断高位标记 int tmp=0; for (int i=0;i<=up;i++) { if (pre!=-1&&abs(pre-i)<2) continue;//如果不合法就跳过 if (i==0&&len==0) tmp+=dfs(pos-1,0,0,-1,limit&&i==a[pos]); else { tmp+=dfs(pos-1,1,i,i,limit&&i==a[pos]); } } if(!limit) f[pos][sta][pre]=tmp; return tmp; } int solve(int x) { int cnt=0; while (x!=0) { a[++cnt]=x%10; x=x/10; } dfs(cnt,0,0,-1,true); } int main() { int n,m; scanf("%d%d",&n,&m); memset(f,-1,sizeof(f)); printf("%d\n",solve(m)-solve(n-1)); }