题意:对于一个数n,如果它能被它各个数位上的除了0的数字整除,则是good number。给定区间[a, b],问good number的数量。(a, b <= 9×10^18)
解法:首先很容易想到数位dp。至于能被一些数整除的问题,就考虑如果一个数能被a和b整除,则能被lcm(a, b)(最小公倍数)整除,而1~9的lcm为2520。然后,由于思维定势,这样之后我顺理成章地想到了用状态压缩的方法表示数x是否含有1~9,这样就妥妥地超时了....其实,最小公倍数不会超过50个,直接记录就好。于是乎,只需要一个d[20][50][2520]的数组即可。
由于我第一次做数位dp的时候,看别人的题解错误理解了d数组的含义(现在很多题解都不写文字说明,在代码里稍微注释一下....真的容易理解偏差),导致我一直以来写的非递归形式的数位dp都是效率比较低的.....而恰巧前面的几道题状态数都很少,所以就过了,而这道题如果用那种方法写出来极限数据大概要跑0.7+s,10组test就跪了......(用比较快的写法10组test最终跑出来为0.4+s)。
我写的代码,定义的d[i][j][k]表示长度为i的数,它各数位的数字的最小公倍数为idx[j],除以2520的余数是k的数一共有多少个,而速度较快的写法定义的d[i][j][k]做数位dp时扫描到第i位时,前面数字的最小公倍数为idx[j],前面的数的余数为k时,要使最终形成的数满足题意,后面i位数总共有多少种可能。具体讲出来好像比较抽象,看代码把...我把错误代码贴出来贴在最后。
Ps:由于每次进位都会*10,所以其实可以只用保存mod 252的余数即可,具体怎么写我把NotOnlySuccess的代码贴出来。
PPs:虽然这道题浪费了很多时间....但是感觉对数位dp的理解更加到位了,也算是有所收获吧....
tag:数位dp, good
我的AC Code:

1 /* 2 * Author: Plumrain 3 * Created Time: 4 * File Name: DP-CF-55D-2.cpp 5 */ 6 #include<iostream> 7 #include<cstdio> 8 #include<cstring> 9 #include<string> 10 #include<cmath> 11 #include<algorithm> 12 #include<vector> 13 #include<cstdlib> 14 #include<sstream> 15 #include<fstream> 16 #include<list> 17 #include<deque> 18 #include<queue> 19 #include<stack> 20 #include<map> 21 #include<set> 22 #include<bitset> 23 #include<cctype> 24 #include<ctime> 25 #include<utility> 26 27 using namespace std; 28 29 #define CLR(x) memset(x, 0, sizeof(x)) 30 #define CLR1(x) memset(x, -1, sizeof(x)) 31 #define PB push_back 32 #define SZ(v) ((int)(v).size()) 33 #define INF 999999999999 34 #define zero(x) (((x)>0?(x):-(x))<eps) 35 #define out(x) cout<<#x<<":"<<(x)<<endl 36 #define tst(a) cout<<#a<<endl 37 #define CINBEQUICKER std::ios::sync_with_stdio(false) 38 39 const double eps = 1e-8; 40 const double PI = atan(1.0)*4; 41 const int maxint = 2147483647; 42 const int mod = 2520; 43 44 typedef vector<int> VI; 45 typedef vector<string> VS; 46 typedef vector<double> VD; 47 typedef pair<int, int> pii; 48 typedef long long int64; 49 50 inline int Mymod (int a, int b) {int x=a%b; if(x<0) x+=b; return x;} 51 52 int dit[20], idx[mod+5]; 53 int64 d[20][50][mod]; 54 55 inline int lcm(int a, int b) 56 { 57 if (!a || !b) return max(a, b); 58 return a / __gcd(a, b) * b; 59 } 60 61 int64 rec(int p, int sum, int cnt) 62 { 63 if (p < 0) return sum % cnt == 0; 64 65 int64& ret = d[p][idx[cnt]][sum]; 66 if (ret != -1) return ret; 67 ret = 0; 68 for (int i = 0; i < 10; ++ i) 69 ret += rec (p-1, (sum*10+i)%mod, lcm(cnt, i)); 70 return ret; 71 } 72 73 int64 gao(int64 x) 74 { 75 if (x < 10) return x; 76 77 int len = 0; 78 while (x){ 79 dit[len++] = x % 10; 80 x /= 10; 81 } 82 83 int sum = 0, cnt = 1; 84 int64 ret = 0; 85 for (int i = len-1; i >= 0; -- i){ 86 for (int t = 0; t < dit[i]; ++ t) 87 ret += rec(i-1, (sum*10+t)%mod, lcm(cnt,t)); 88 89 cnt = lcm(cnt, dit[i]); 90 sum = (sum*10 + dit[i]) % mod; 91 } 92 return ret; 93 } 94 95 void init() 96 { 97 CLR1 (d); 98 int all = 0; 99 for (int i = 1; i <= mod; ++ i) 100 if (mod % i == 0) idx[i] = all++; 101 } 102 103 int main() 104 { 105 // freopen("a.in","r",stdin); 106 // freopen("a.out","w",stdout); 107 // std::ios::sync_with_stdio(false); 108 init(); 109 int T; 110 scanf ("%d", &T); 111 while (T--){ 112 int64 a, b; 113 cin >> a >> b; 114 cout << gao(b+1) - gao(a) << endl; 115 } 116 return 0; 117 }
NotOnluySuccess:
我的TLE代码(非递归):

1 /* 2 * Author: Plumrain 3 * Created Time: 2013-12-17 19:56 4 * File Name: DP-CF-55D.cpp 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 #include <string> 10 #include <cmath> 11 #include <algorithm> 12 #include <vector> 13 #include <cstdlib> 14 #include <sstream> 15 #include <fstream> 16 #include <list> 17 #include <deque> 18 #include <queue> 19 #include <stack> 20 #include <map> 21 #include <set> 22 #include <bitset> 23 #include <cctype> 24 #include <ctime> 25 #include <utility> 26 27 using namespace std; 28 29 #define CLR(x) memset(x, 0, sizeof(x)) 30 #define CLR1(x) memset(x, -1, sizeof(x)) 31 #define PB push_back 32 #define SZ(v) ((int)(v).size()) 33 #define ALL(t) t.begin(),t.end() 34 #define INF 999999999999 35 #define zero(x) (((x)>0?(x):-(x))<eps) 36 #define out(x) cout<<#x<<":"<<(x)<<endl 37 #define tst(a) cout<<#a<<endl 38 #define CINBEQUICKER std::ios::sync_with_stdio(false) 39 40 const double eps = 1e-8; 41 const double PI = atan(1.0)*4; 42 const int maxint = 2147483647; 43 const int N = 1 << 10; 44 const int mod = 2520; 45 46 typedef vector<int> VI; 47 typedef vector<string> VS; 48 typedef vector<double> VD; 49 typedef pair<int, int> pii; 50 typedef long long Int64; 51 52 inline int Mymod (int a, int b) {int x=a%b; if(x<0) x+=b; return x;} 53 54 Int64 dit[30]; 55 Int64 ten[30], d[20][50][mod+5]; 56 int idx[50], num[mod+1], all; 57 58 int lcm(int a, int b) 59 { 60 if ((!a) || (!b)) return max(a, b); 61 return a / __gcd(a, b) * b; 62 } 63 64 void init() 65 { 66 ten[0] = 1; 67 for (int i = 1; i < 19; ++ i) 68 ten[i] = ten[i-1] * 10; 69 70 CLR1 (num); CLR (idx); 71 all = 0; 72 for (int i = 1; i <= mod; ++ i) if (mod % i == 0){ 73 idx[all] = i; num[i] = all++; 74 } 75 76 CLR (d); 77 d[1][0][0] = 1; 78 for (int i = 1; i < 10; ++ i) 79 d[1][num[i]][i] = 1; 80 81 for (int i = 2; i < 19; ++ i){ 82 for (int j = 0; j < all; ++ j) 83 for (int k = 0; k < mod; ++ k) 84 for (int t = 0; t < 10; ++ t){ 85 int tmp = lcm(t, idx[j]); 86 d[i][num[tmp]][(k*10+t)%mod] += d[i-1][j][k]; 87 } 88 } 89 } 90 91 Int64 gao(Int64 x) 92 { 93 if (x < 10) return x+1; 94 95 int len = 0; 96 while (x){ 97 dit[len++] = x % 10; 98 x /= 10; 99 } 100 101 int flag = 0, cnt = 0; 102 Int64 ret = 0; 103 for (int i = len-1; i; -- i){ 104 for (int j = 0; j < all; ++ j) 105 for (int k = 0; k < mod; ++ k) 106 for (int t = 0; t < dit[i]; ++ t){ 107 int tmp = lcm(t, lcm(flag, idx[j])); 108 if (((cnt + t*ten[i] + k) % tmp) == 0) 109 ret += d[i][j][k]; 110 } 111 112 flag = lcm(flag, dit[i]); 113 cnt = (cnt + dit[i]*ten[i]) % mod; 114 } 115 for (int i = 0; i <= dit[0]; ++ i) 116 if (((i+cnt) % lcm(flag, i)) == 0) 117 ++ ret; 118 return ret; 119 } 120 121 122 int main() 123 { 124 init(); 125 int T; 126 scanf ("%d", &T); 127 while (T--){ 128 Int64 a, b; 129 cin >> a >> b; 130 cout << gao(b) - gao(a-1) << endl; 131 } 132 return 0; 133 }