1. 程式人生 > >「 Luogu P2657 」 windy數

「 Luogu P2657 」 windy數

num 至少 color using sca printf span set spa

# 題目大意

給出區間 $[a,b]$,求出區間中有多少數滿足下列兩個條件

  • 不含有前導 $0$。
  • 相鄰兩個數字之差的絕對值至少是 $2$。

# 解題思路

數位 $DP$,用記憶化搜索來實現。設 $dp[i][j]$ 表示現在已經枚舉到第 $i$ 位,第 $i+1$ 位是 $j$ 時一共有多少滿足條件的數。

還是直接看代碼裏的註釋吧。

# 放上代碼

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using
namespace std; const int HA = 233; //這裏要設置為233,不能設置為int_max,會炸 int n, m, dp[15][15], num[15]; inline int Abs(int x) { return x>0 ? x : -x; } inline int dfs(int l, int pre, bool limit, bool Zero) { if(l == 0) return 1; //如果所有的位置都枚舉完了,這顯然就是一種可行方案 if(!Zero && !limit && dp[l][pre]) return
dp[l][pre]; //沒有前導0和限制是才能用通用答案 int ans = 0, mx = limit ? num[l] : 9; for(int i=0; i<=mx; i++) { if(Abs(i-pre) < 2) continue; int tmp = (i==0 && Zero) ? -HA : i; //如果有前導0並且現在這一位是0,那就設置為一個負數 ans += dfs(l-1, tmp, limit && (i == mx), tmp==-HA);
//前面的位有限制並且這一位到達了最高的數字那麽限制就可以傳遞給下一位 } if(!limit && !Zero) dp[l][pre] = ans; //沒有限制沒有前導0才能夠成為通用的答案 return ans; } inline int solve(int x) { //將x分解 memset(num, 0, sizeof(num)); int k = 0; while (x) { num[++k] = x % 10; x /= 10; } return dfs(k, -HA, true, true); //第k位之前的一定是前導0 } int main() { scanf("%d%d", &n, &m); printf("%d", solve(m)-solve(n-1)); //類似前綴和 }

「 Luogu P2657 」 windy數