2
#include <stdio.h> #include <stdlib.h> #include <string.h> int num[20], ln; __int64 f[20][2521][50]; int hash[2521]; void swap(int &a, int &b){ int t = a; a = b; b = t; } int gcd(int a, int b){ int c; while(b){ c = a % b; a = b; b = c; } return a; } int Lcm(int a, int b){ // printf("Lcm %d, %d\n", a, b); if (a < b) swap(a, b); if (b == 0) return a; return a * b / gcd(a, b); } __int64 dfs(int i, int mod, int mark, bool flag){ int p, high; __int64 ret; // printf("dfs(%d, %d, %d, %d)\n", i, mod, mark, flag); if (i <= 0) return (mod % mark == 0); if (!flag && ~f[i][mod][hash[mark]]) return f[i][mod][hash[mark]]; high = flag ? num[i] : 9; ret = 0; for (p = 0; p <= high; p++){ // printf("p = %d\n", p); ret += dfs(i - 1, (mod * 10 + p) % 2520, Lcm(mark, p), flag && (p == high)); } if (!flag) f[i][mod][hash[mark]] = ret; return ret; } void trans(__int64 n){ ln = 0; while(n){ num[++ln] = n % 10; n = n / 10; } } __int64 calc(__int64 n){ trans(n); return dfs(ln, 0, 1, true); } void init(){ int i, j, k, l, cnt = 0; memset(f, 0xff, sizeof(f)); hash[0] = 0; for (i = 1; i < 10; i *= 2) for (j = 1; j < 10; j *= 3) for (k = 1; k < 10; k *= 5) for (l = 1; l < 10; l *= 7){ hash[i * j * k * l] = ++cnt; } } int main(){ __int64 L, R; int T; init(); scanf("%d", &T); while(T--){ scanf("%I64d %I64d", &L, &R); printf("%I64d\n", calc(R) - calc(L - 1)); } return 0; } /************************** 按位dp 表示看解题报告后写的。。见http://hi.baidu.com/%B1%BFС%BA%A2_shw/blog/item/a30e5c230dffdfe7d6cae200.html 开始时想不通怎么判是否整除所有位的数,想存模2..9的所有余数的情况。。。 其实根本没必要,我们希望知道一个数n是否整除LCM{n的每位数}(记做mark),而LCM{2...9} = 2520的,一定能整除mark, 所以 mark | n <=> mark | (n % 2520) 或者说 n % mark = (k * 2520 + k1) % mark = k1 % mark 于是记录下模2520和当前lcm(程序中为mark),判断下模2520余出来的那部分能否整除当前lcm即可 为方便存储,mark一共只有4 * 3 * 2 * 2 = 48种(分别代表2,3,5,7在小于10可能取到的幂数),hash一下节省空间 话说这样的空间消耗,真怕会爆掉的。。。但在codeforce里慢慢地跑了300ms+过了Accepted。。。 还有更进一步优化,详见http://codeforces.ru/blog/entry/1109?locale=en **************************/