51Nod-1284 2 3 5 7的倍數【數位DP+記憶化搜尋】
阿新 • • 發佈:2019-01-06
給出一個數N,求1至N中,有多少個數不是2 3 5 7的倍數。 例如N = 10,只有1不是2 3 5 7的倍數。
Input
輸入1個數N(1 <= N <= 10^18)。
Output
輸出不是2 3 5 7的倍數的數共有多少。
Input示例
10
Output示例
1
問題分析:
這是一個數位DP問題,用記憶化搜尋實現。
程式說明:(無)
題記:(略)
AC的C++語言程式如下:
/* 51Nod-1284 2 3 5 7的倍數 */ #include <bits/stdc++.h> using namespace std; typedef long long LL; const int M2 = 2; const int M3 = 3; const int M5 = 5; const int M7 = 7; const int N = 20; // 位數,long long型別不超過20位 int digits[N + 1]; LL dp[N][M2][M3][M5][M7]; // dp[i][m2][m3][m5][m7]-共i位,其中m2-m7分別為2 3 5 7的餘數 /* * 引數: * pos - 數位位置,即當前處理數的第幾位,從高位開始 * m2-m7 - 2 3 5 7的餘數 * limit - 是否為數位上界(最大數字) */ LL dfs(int pos, int r2, int r3, int r5, int r7, bool limit) { if(pos == -1) { // 遞迴邊界,已經列舉結束,則返回1的數量 if(r2 == 0 || r3 == 0 || r5 == 0 || r7 == 0) return 0; else return 1; } if(!limit && dp[pos][r2][r3][r5][r7] != -1) // 已經搜尋過的不再搜尋,直接使用之前的計算結果 return dp[pos][r2][r3][r5][r7]; // 計數 LL ans = 0; int maxd = limit ? digits[pos] : 9; // 列舉數字,如果數字不同則列舉0-9 for(int i = 0; i <= maxd; i++) { ans += dfs(pos - 1, (r2 * 10 + i) % M2, (r3 * 10 + i) % M3, (r5 * 10 + i) % M5, (r7 * 10 + i) % M7, limit && i == maxd); } if(!limit) dp[pos][r2][r3][r5][r7] = ans; return ans; } // 計算[0,n]中不是2 3 5 7倍數數的數量之和 LL solve(LL n) { int len = 0; while(n) { digits[len++] = n % 10; n /= 10; } return dfs(len - 1, 0, 0, 0, 0, true); } int main() { memset(dp, -1, sizeof(dp)); LL n; while(~scanf("%lld", &n)) printf("%lld\n", solve(n)); return 0; }