首页 > 代码库 > HDU 4937 Lucky Number 搜索
HDU 4937 Lucky Number 搜索
题意:
给你一个数,求在多少种不同的进制下这个数每一位都是3、4、5、6中的一个。
思路:
搜索。枚举这个数在任意进制下的表示,判断是否合法。当数字只有3、4、5、6时,必定有无穷种。
因为数字太大,所以直接枚举必定会超时。
下面有两种剪枝的方法:
1. 先枚举最后一位的情况。 假设数字n在base进制下表示为 a[n]...a[0],即 n = a[0] + a[1]*base^1 + ... + a[n]*base^n。
则 n - a[0] = a[1]*base^1 + ... + a[n]*base^n = base * (a[1] + ... + a[n]*base^(n-1) )。 即n - a[0] 是base 的倍数。
所以,我们可以确定base是n-a[0]的因子。 所以,我们可以先枚举在某个进制下的末位a[0],然后在枚举 n-a[i]的因子就好了。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <string> 8 #include <queue> 9 #include <stack> 10 #include <vector> 11 #include <map> 12 #include <set> 13 #include <functional> 14 #include <time.h> 15 16 using namespace std; 17 18 typedef __int64 ll; 19 20 const int INF = 1<<30; 21 const int MAXN = (int) 1e6+5; 22 23 int Prime[MAXN], len; 24 bool is[MAXN]; 25 26 ll f[20]; 27 int cnt[20], num; 28 29 void factor(ll x) { //分解质因数 30 num = 0; 31 if (x==1) return ; 32 for (int i = 0; i < len; i++) if ((x%Prime[i])==0) { 33 f[num] = Prime[i]; 34 cnt[num] = 0; 35 while (x%Prime[i]==0) { 36 x /= Prime[i]; 37 cnt[num]++; 38 } 39 num++; 40 if (x==1) break; 41 if (x<Prime[len-1] && !is[x]) break; 42 } 43 if (x!=1) { 44 f[num] = x; 45 cnt[num++] = 1; 46 } 47 } 48 49 ll n; 50 int ans; 51 52 void dfs(ll base, int deep) { //枚举可以重复的组合 53 if (deep==num) { 54 if (base < 4) return ; 55 ll tmp = n, t; 56 while (tmp) { 57 t = tmp%base; 58 if (!(2<t&&t<7)) return ; 59 tmp /= base; 60 } 61 ans++; 62 return ; 63 } 64 ll tmp = base; 65 for (int i = 0; i <= cnt[deep]; i++) { 66 dfs(tmp, deep+1); 67 tmp *= f[deep]; 68 } 69 } 70 71 void solve() { 72 scanf("%I64d", &n); 73 ans = 0; 74 if (2<n&&n<7) { 75 puts("-1"); 76 return ; 77 } 78 for (int i = 3; i < 7; i++) if (n-i>10) { //枚举末位 79 factor(n-i); 80 dfs(1LL, 0); 81 } 82 printf("%d\n", ans); 83 } 84 85 int main() { 86 #ifdef Phantom01 87 freopen("HDU4937.in", "r", stdin); 88 #endif //Phantom01 89 90 memset(is, false, sizeof(is)); 91 len = 0; 92 for (int i = 2; i < MAXN; i++) if (!is[i]) { 93 Prime[len++] = i; 94 for (ll j = i*2; j < MAXN; j+=i) 95 is[j] = true; 96 } 97 98 int T; 99 scanf("%d", &T);100 for (int i = 1; i <= T; i++) {101 printf("Case #%d: ", i);102 solve();103 }104 105 return 0;106 }
2. 当n在base进制下为一位数的时候,为3、4、5、6,则一定存在无穷种进制下都是这个一位数。
两位数时, n = a[1]*base + a[0]
三位数时,n = a[2]*base^2 + a[1]*base + a[0]
因此,在n是两位数或者三位数时,我们可以枚举这个两位数或者三位数,求得有多少个base能得到这个两位数或三位数。
当 n 是4位数或者更多时, n = a[0] + a[1]*base^1 + ... + a[n]*base^n > 3*base^4 。即 3*base^4 < n <= 1e12。 所以,此时base < 7000。
所以,我们可以暴力枚举n是四位数的情况,而这时的base不会大于7000 。所以就不会超时了。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <string> 8 #include <queue> 9 #include <stack> 10 #include <vector> 11 #include <map> 12 #include <set> 13 #include <functional> 14 #include <time.h> 15 16 using namespace std; 17 18 typedef __int64 ll; 19 const int INF = 1<<30; 20 21 ll n; 22 int ans; 23 24 inline int function1(ll a, ll b) { //n = a*base + b 25 if (((n-b)%a)!=0) return 0; //如果不是整数 26 ll tmp = (n-b)/a; 27 if (a>=tmp || b>=tmp) return 0; //如果位数大于进制数 28 return 1; 29 } 30 31 inline int function2(ll a, ll b, ll c) { //n = a*base^2 + b*base + c 32 c -= n; 33 ll t1 = b*b-4*a*c; 34 if (t1<0) return 0; 35 ll t2 = (ll) sqrt((double)t1); 36 if (t2*t2!=t1) return 0; 37 if (((t2-b)%(2*a))!=0) return 0; 38 t1 = (t2-b)/2/a; 39 if (t1<=a || t1<=b || t1<=c || t1<=0) return 0; 40 return 1; 41 } 42 43 inline bool check(int base) { 44 ll t = n, cnt = 0, tt; 45 while (t>0) { 46 tt = t%base; 47 if (!(2<tt&&tt<7)) return false; 48 t /= base; 49 cnt++; 50 } 51 return cnt>3; 52 } 53 54 void solve() { 55 scanf("%I64d", &n); 56 57 if (2<n&&n<7) { 58 puts("-1"); 59 return ; 60 } 61 62 ans = 0; 63 for (int i = 3; i < 7; i++) { 64 for (int j = 3; j < 7; j++) { 65 for (int k = 3; k < 7; k++) { 66 ans += function2(i, j, k); 67 } 68 ans += function1(i, j); 69 } 70 } 71 ll len = min(n, 7000ll); 72 for (int i = 4; i < len; i++) 73 ans += check(i) ? 1 : 0; 74 75 printf("%d\n", ans); 76 } 77 78 79 void ttt(int i) { 80 int t = 255; 81 printf("%d:", i); 82 while (t) { 83 printf("%d ", t%i); 84 t /= i; 85 } 86 puts(""); 87 } 88 89 int main() { 90 #ifdef Phantom01 91 freopen("HDU4937.in", "r", stdin); 92 // freopen("HDU4937.txt", "w", stdout); 93 #endif //Phantom01 94 95 int T; 96 scanf("%d", &T); 97 for (int i = 1; i <= T; i++) { 98 printf("Case #%d: ", i); 99 solve();100 }101 102 return 0;103 }