4kyu N linear
题目背景:
Task
Consider an integer sequence U(m) defined as:
1. m is a given non-empty set of positive integers.
2. U(m)[0] = 1, the first number is always 1.
3. For each x in U(m), and each y in m, x * y + 1 must also be in U(m).
4. No other numbers are in U(m).
5. U(m) is sorted, with no duplicates.
Implement n_linear or nLinear: given a set of postive integers m, and an index n, find U(m)[n], the nth value in the U(m) sequence.
Example
U(2, 3) = [1, 3, 4, 7, 9, 10, 13, 15, 19, 21, 22, 27, ...]
U(5, 7, 8) = [1, 6, 8, 9, 31, 41, 43, 46, 49, 57, 64, 65, 73, 156, 206, ...]
题目分析:
本道题目,是先前提到的 Twice linear的衍生版,难度上自然是提升了,如果再试图用 Twice linear 的思路去解,显然是行不通的。分析之前的方法,当 U(2, 3)时,用两个队列分别存储 乘子为2 、 3的数据,这个问题最大的问题是为了思路简单易懂牺牲了空间,即一股脑地把所有元素都塞进了队列中去慢慢比较。如果说 m 中的因子彼此差距特别大,如 (2, 200, 1000)这样会浪费了很多空间,导致内存溢出。所以本道题的思路就是去优化空间,希望不占用那么大的空间。最浅显的思路就是打标签,用标签去标指每个队列下一次填充的元素应是什么,而我的解题代码也是按照这个思路去解决的,碍于具体思路的表述比较麻烦,我就直接奉上AC代码:
AC代码:
#include <queue>
uint32_t n_linear(const std::set<uint32_t>& m, size_t n) {
std::vector<uint32_t> m1(m.begin(), m.end());
int len = m.size();
std::vector<uint32_t> idx(len);
std::vector<std::queue<uint32_t>> Q(len);
std::vector<uint32_t> res{1};
for ( int i = 0; i < m1.size(); i++ ) Q[i].push(m1[i] + 1);
size_t cnt = 0;
while( cnt != n ) {
uint64_t min = ULLONG_MAX;
for ( int i = 0; i < len; i++ ) {
if ( Q[i].front() < min ) min = Q[i].front();
}
res.push_back(min);
for ( int i = 0; i < len; i++ ) {
if ( Q[i].front() == min ) {
Q[i].pop();
idx[i]++;
Q[i].push(res[idx[i]] * m1[i] + 1);
}
}
cnt++;
}
return res.back();
}