M - windy数
这个数位dp还比较明显,而且也比较好写,不过还是被我写搓了,伤心ing
这个数位dp,就是dp这个状态需要好好想想,还有就是这个前导0的问题,这个就是需要认真看题目。
我开始直接定义的一维dp,dp[i]定义为i位个数满足条件的数有多少
但是这个状态定义的是不完整的,因为第i位可以是1,2,3,4.。。。
这样子就不对了,所以一维是不够的,需要二维。
dp[i][j]表示有i位数,且最高位是j的满足条件的数有多少。
这个状态定义完之后就是前导0的处理了,我一开始以为这个可以不用判断前导0,但是实际上这个是需要判断前导0的
因为如果有前导0,那么这个数就可以随意放,但是如果没有就必须和前面的数进行比较,
所以这个还是要进行前导0 的判断的,如果你不进行前导0的判断,那这个代码就会写的很麻烦,而且还不一定写对。
我们先假设pre==-2因为abs(0-(-2))>=2这个意思就是说如果有前导0 就是对的,可以自行理解一下代码。
#include <cstdio> #include <cstdlib> #include <cstring> #include <queue> #include <algorithm> #include <vector> #include <iostream> #define inf 0x3f3f3f3f3f3f3f3f using namespace std; const int maxn = 1010; typedef long long ll; ll dp[100][20];//前面i个数满足条件的数有多少 int a[maxn]; ll dfs(int pos,int pre,bool limit,bool lead) { if (pos == -1) return 1; if (!limit &&!lead &&dp[pos][pre] != -1) return dp[pos][pre]; int up = limit ? a[pos] : 9; ll ans = 0; for(int i=0;i<=up;i++) { if (abs(i - pre) < 2) continue; int p = i; if (lead&&i==0) p = -2; ans += dfs(pos - 1, p, limit && (i == up), p == -2); } if (!limit&&!lead) dp[pos][pre] = ans; return ans; } ll solve(int x) { int pos = 0; while(x) { a[pos++] = x % 10; x /= 10; } return dfs(pos - 1, -2, 1, 1); } int main() { int l, r; memset(dp, -1, sizeof(dp)); while(scanf("%d%d",&l,&r)!=EOF) { ll ans = solve(r); ll ana = solve(l - 1); cout << ans - ana<< endl; } return 0; }