CodeForces 55D Beautiful numbers

题意:对于一个数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 }
View Code

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 }
View Code

 

 

 

 

posted @ 2013-12-18 11:52  Plumrain  阅读(270)  评论(0编辑  收藏  举报