Codeforces 55D
基本的数位DP,注意记录那些状态可以用最小的空间判断出整除性。
#include <cstdio> #include <cstring> using namespace std; #define D(x) const int MAX_DIGIT_NUM = 20; int f[MAX_DIGIT_NUM]; long long memoize[MAX_DIGIT_NUM][5][7][8][9][1 << 8]; bool contain[10]; int to_digits(long long n) { int ret = 0; while (n > 0) { f[ret++] = n % 10; n /= 10; } return ret; } bool check(int r5, int r7, int r8, int r9, int status) { D(printf("%d%d%d%d %d\n", r5, r7, r8, r9, status)); memset(contain, 0, sizeof(contain)); int i = 2; while (status) { contain[i++] = status & 1; status >>= 1; } if (contain[2] && r8 % 2) { return false; } if (contain[3] && r9 % 3) { return false; } if (contain[4] && r8 % 4) { return false; } if (contain[5] && r5 % 5) { return false; } if (contain[6] && (r8 % 2 || r9 % 3)) { return false; } if (contain[7] && r7) { return false; } if (contain[8] && r8 % 8) { return false; } if (contain[9] && r9 % 9) { return false; } D(puts("***")); return true; } long long dfs(int digit, bool less, int r5, int r7, int r8, int r9, int status) { D(printf("%d\n", status)); if (digit < 0) { return check(r5, r7, r8, r9, status); } if (less && memoize[digit][r5][r7][r8][r9][status] != -1) { return memoize[digit][r5][r7][r8][r9][status]; } int limit = less ? 9 : f[digit]; long long ret = 0; for (int i = 0; i <= limit; i++) { int next_status = i < 2 ? status : status | (1 << (i - 2)); ret += dfs(digit - 1, less || i < f[digit], i % 5, (r7 * 10 + i) % 7, (r8 * 10 + i) % 8, (r9 * 10 + i) % 9, next_status); } if (less) { memoize[digit][r5][r7][r8][r9][status] = ret; } return ret; } long long work(long long n) { if (n == 0) { return 1; } int len = to_digits(n); return dfs(len - 1, false, 0, 0, 0, 0, 0); } int main() { int t; scanf("%d", &t); memset(memoize, -1, sizeof(memoize)); while (t--) { long long a, b; scanf("%I64d%I64d", &a, &b); printf("%I64d\n", work(b) - work(a - 1)); } return 0; }