51Nod 1010
问题描述: 假如整数n除以m,结果是无余数的整数,那么我们称 m 就是 n 的因子。 假如一个数, 他的因子只包含 2、3、5,我们则称这个数是一个好数。 小A 想知道大于或等于 n 的最小的好数是多少?
输入描述:
第1行:一个数 t,表示后面用作输入测试的数的数量。
第 2 ~ t+1行:每行1个数 n. 1<=n<=1e18.
输出描述:
共 t 行,每个样例输出 1 个数,输出大于等于 n 的最小的只包含因子 2、3、 5的数.
示例:
输入 #1:
4
1
13
17
22
输出 #1:
2
15
18
24
基本思路:找出所有小于1e18并且只由2,3,5相乘的数,存入数组,排序再二分查找.
下面有两种做法:
1
找出所有由2相乘的数,如2,4,8…存入一个数组.
3和5也一样.
枚举2 ^a + 3 ^b + 5 ^c<1e18.
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N = 5e5;
const int M = 100;
const ll inf = 1e18;
long long a[N], a2[M], a3[M], a5[M];
int cnt = 0;
void f() {
//分块存入数组这部分,其实可以用pow()解决
a2[0] = a3[0] = a5[0] = 1;
int c2, c3, c5;
for (int i = 1; i <= 60; i++) {
a2[i] = a2[i - 1] * 2;
if (a2[i] > inf) {
c2 = i;
break;
}
}
for (int i = 1; i <= 40; i++) {
a3[i] = a3[i - 1] * 3;
if (a3[i] > inf) {
c3 = i;
break;
}
}
for (int i = 1; i <= 30; i++) {
a5[i] = a5[i - 1] * 5;
if (a5[i] > inf) {
c5 = i;
break;
}
}
for (int i = 0; i < c2; i++) {
for (int j = 0; j < c3; j++) {
for (int k = 0; k < c5; k++) {
//注意这里,连乘的话会爆long long
//因为弹出当前循环,j还是增加,i和j的部分就可能爆了
if (a2[i] > (inf / (a3[j] * a5[k]))) {
break;
}
a[cnt++] = a2[i] * a3[j] * a5[k];
}
}
}
}
int main() {
ll t, n, x;
f();
scanf("%lld", &t);
sort(a, a + cnt);
while (t--) {
scanf("%lld", &n);
//第一项是1,不要
x = lower_bound(a + 1, a + cnt, n) - a;
printf("%lld\n", a[x]);
}
return 0;
}
2
dfs搜索,三个分岔,乘以2,3,5.
通过代码1 ,知道大概有1e5个数.
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const int N = 2e5;
const ll inf = 1e18;
map<ll, int> mp;
ll a[N];
int cnt = 0;
void dfs(ll sum,ll x){
sum *= x;
//剪枝,有的数据就不用再搜索了
//不然搜索次数超过int范围了
if(sum>inf||mp[sum]){
return;
}
a[cnt++] = sum;
mp[sum]++;
dfs(sum, 2);
dfs(sum, 3);
dfs(sum, 5);
}
int main(){
ll t, n;
dfs(1, 1);
scanf("%lld", &t);
sort(a, a + cnt);
while(t--){
scanf("%lld", &n);
int x = lower_bound(a+1, a + cnt, n) - a;
printf("%lld\n", a[x]);
}
return 0;
}