51nod 1010 只包含因子2 3 5的数
题目链接:http://class.51nod.com/Challenge/Problem.html#problemId=1010
一、题目描述
K的因子中只包含2 3 5。满足条件的前10个数是:2,3,4,5,6,8,9,10,12,15。
所有这样的K组成了一个序列S,现在给出一个数n,求S中 >= 给定数的最小的数。
例如:n = 13,S中 >= 13的最小的数是15,所以输出15。
输入描述
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 10000) 第2 - T + 1行:每行1个数N(1 <= N <= 10^18)
输出描述
样例输入
5 1 8 13 35 77
样例输出
2 8 15 36 80
二、思路描述
尽管N的范围达到1e18,但实际符合条件的数字却并不多,不到15000个。
这点很关键,所以我们可以预先处理出1e18以内,所有符合条件的数字。
获取符合条件的数字的方法很多,我们介绍一下如何用优先队列解决这个问题。
我们将2,3,5放入优先队列,每次从队列中取出最小的数,把这个数分别乘以2,3,5后,再放回到优先队列中。
这样就可以得到所有的符合条件的数。
需要注意的是,有些数字会重复出现,例如:60,有可能通过12 * 5得到,也可能通过20*3,30*2得到,需要去掉重复出现的。
具体方法是在弹出队列时如果发现与上一个数相同,则不再处理。
在这里我们也复习一下怎么在优先队列里找到最小数:
只要是这么写的,就说明q这个优先队列是从小到大排列的:
priority_queue <int,vector<int>,greater<int> > q;
现在给优先队列的基本操作(只在本题中使用的基本操作):
priority_queue <long long, vector <long long>, greater <long long> > que;
定义一个从小到大排列的优先队列
que.push(1); 往优先队列que中存入1这个数
que.size() 返回que里元素个数
que.top() 这个只能在优先队列里使用,不能再普通队列里使用。
如果是从小到大排列的优先队列。那么第一个肯定是最小的,最后一个是最大的。那么返回第一个数字(在这道题里是返回最小的)
在这里我们也复习一下什么是vector不定长数组
要定义vector不定长数组的原因主要有2个
第一个:vector不定长数组有个函数叫做value.begin()和value.end()。
如果使用优先队列的话,lower_bound()函数的第二个参数(结束下标)就不知道填什么了
但是如果把优先队列去重以后放到vector不定长数组后就可以使用value.end()函数了,lower_bound()函数的第二个参数就可以填了
第二个:因为vector不定长数组是没有长度限制的,虽然我们知道实际符合条件的数字不到15000个,但是实际上多少个也不是很确定的。
所以,如果使用vector的话就不需要考虑长度了
vector不定长数组就是一个数组,只不过没有长度限制。
但是vector不定长数组的操作(例如插入或删除一个数)都和普通数组不一样
现在给vector的基本操作(只在本题中使用的基本操作):
vector <long long> value; 定义一个不定长数组value
value.push_back(v); 往value不定长数组中插入一个数v
value.begin() value开始的下标
value.end() value结束的下标
在这里我们也复习一下什么是lower_bound()和upper_bound()。
lower_bound是查找一个数组中大于等于一个数的最小值。
以下是规定写法:
lower_bound(开始的下标,结束的下标,查找的那个数) - 数组名
————————————————————————————————
upper_bound是查找一个数组中大于一个数的最小值
以下是规定写法:
upper_bound(开始的下标,结束的下标,查找的那个数) - 数组名
在这道题中我们可以利用lower_bound()函数来求出vector不定长数组中大于等于n的最小值
三、代码
#include<queue>
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
long long cnt, t, n[10010], maxnumber=1e18, tmp;
priority_queue <long long, vector <long long>, greater <long long> > que;
vector <long long> values;
void pre(){
que.push(1);
while(que.size() > 0){//只要里面还有数
tmp = que.top();//tmp=最小数
if(tmp > maxnumber){//如果这个最小数太大了,不算了
break;
}
while(que.size() > 0 && tmp == que.top()){//去掉重复数字并且把最小数字弹出去
que.pop();
}
if(tmp > 1){
values.push_back(tmp);
}
que.push(tmp*2);//把最小的数乘上2后也放进优先队列里
que.push(tmp*3);//把最小的数乘上3后也放进优先队列里
que.push(tmp*5);//把最小的数乘上5后也放进优先队列里
}
}
int main(){
cin >> t;
for(int i = 0;i < t;i++){
cin >> n[i];
}
pre();
for(int i = 0;i < t;i++){
cnt = values[lower_bound(values.begin(), values.end(), n[i]) - values.begin()];
cout << cnt << endl;
}
return 0;
}