BZOJ1026 [SCOI2009]windy數
阿新 • • 發佈:2017-06-11
pan cpp 所有 scanf return -- -1 || !=
1 10
【輸入樣例二】
25 50
9
【輸出樣例二】
20
Description
windy定義了一種windy數。不含前導零且相鄰兩個數字之差至少為2的正整數被稱為windy數。 windy想知道,
在A和B之間,包括A和B,總共有多少個windy數?
Input
包含兩個整數,A B。
Output
一個整數
Sample Input
【輸入樣例一】1 10
【輸入樣例二】
25 50
Sample Output
【輸出樣例一】9
【輸出樣例二】
20
HINT
【數據規模和約定】
100%的數據,滿足 1 <= A <= B <= 2000000000 。
題解
裸數位dp。。。。不過這數據範圍不大對勁啊,不應該是$10^100000$那種,然後對$10^9+7$取模嗎。。。
首先將問題轉化成1到N的windy數個數。
設N的十進制表示有n位,定義$f_{i,j}$為只考慮第n-1位(第0位至第n-1位,一共n位)到第i位時,小於N的末尾是j的windy數個數,那麽有
$$f_{i,j} = [i<n-1\;and\;isWindyNumber(N_{i+1..n-1})\;and\;j<N_i\;and\;abs(N_{i+1}-j)\geq 2] + [i<n-1\;and\;j>0] + \sum_{0 < k < 10, \\ abs(k - j) \geq 2}f_{i+1,k}$$
其中第一項表示前面所有位都與N相同,第i位比N小,第二項表示一位數,第三項表示其它情況。
最後如果N是windy數那麽再加一。
附代碼:
#include <algorithm> #include <cstdio> int p[10]; int f[10][10]; inline bool check(int a, int b) { return std::abs(a - b) >= 2; } int count(int N) { if (!N) return 0; int n = 0; while (N) { p[n++] = N % 10; N /= 10; } p[n] = 0; bool ok = true; for (int j = 0; j < 10; ++j) f[n][j] = 0; for (int i = n - 1; ~i; --i) { for (int j = 0; j < 10; ++j) { f[i][j] = ok && (j < p[i]) && ((i == n - 1 && j) || check(p[i + 1], j)); if (i != n - 1 && j) ++f[i][j]; for (int k = 0; k < 10; ++k) if (check(k, j)) f[i][j] += f[i + 1][k]; } if (i < n - 1 && !check(p[i], p[i + 1])) ok = false; } int ans = ok; for (int i = 0; i < 10; ++i) ans += f[0][i]; return ans; } int main() { int A, B; scanf("%d%d", &A, &B); printf("%d\n", count(B) - count(A - 1)); return 0; }
BZOJ1026 [SCOI2009]windy數