传送门:http://codeforces.com/contest/912/problem/E
有整数集上的映射G:S→T。其中S为一个质数集;T为一个整数集:其中,每一个数的所有质因子均为S中的元素。现给定一个n元的质数集S,求T=G(S)中的第k小的整数。
首先考虑集合T=G(S)的构造:
设质数集S={pi|i=1,2,...,n},则$T=G(S)={prod_{i=1}^{n}{p_i^{a_i}}|a_i=0,1,2,cdots;i=1,2,cdots,n}$。
集合T=G(S)可以通过DFS构造,这里用std::vector实现:
void dfs(int idx, int64_t cur) { if (idx == s.size()) { gs.push_back(cur); return; } if (s[idx] <= inf / cur) dfs(idx, cur * s[idx]); dfs(idx + 1, cur); }
考虑将S划分成两个集合A、B,划分满足:A∪B=S,A∩B=Ø,则G(A)∩G(B)=Ø。划分的方式可以是按照下标的奇偶性划分,即A={pi|i=1,3,...;i≤n},B={pi|i=2,4,...;i≤n}。于是,占用空间由|G(S)|,降至|G(A)|+|G(B)|。同理,可以通过DFS构造集合G(A)、G(B)。
设order(x)返回x在集合T中的“序号”k:若集合T中第k小的数为tk,则tk≤x<tk+1。可以在O(|G(A)|+|G(B)|)的时间复杂度下实现这个函数。
之后,在0~inf上查找。采用二分查找法。查找的时间复杂度为O((|G(A)|+|G(B)|)·log inf)。
参考程序如下:
#include <bits/stdc++.h> using namespace std; const int64_t inf = (int64_t)1e18; vector<int64_t> a[2], g[2]; void dfs(int obj, int idx, int64_t cur) { if (idx == a[obj].size()) { g[obj].push_back(cur); return; } if (a[obj][idx] <= inf / cur) dfs(obj, idx, cur * a[obj][idx]); dfs(obj, idx + 1, cur); } int order(int64_t x) { int res = 0; int i = g[0].size() - 1, j = 0; for (; i >= 0; i--) { for (; j < g[1].size() && g[1][j] <= x / g[0][i]; j++); res += j; } return res; } int main(void) { int n, k; scanf("%d", &n); for (int i = 0; i < n; i++) { int p; scanf("%d", &p); a[i & 1].push_back(p); } scanf("%d", &k); //generate sequences g-s. dfs(0, 0, 1LL); sort(g[0].begin(), g[0].end()); dfs(1, 0, 1LL); sort(g[1].begin(), g[1].end()); //binary search. int64_t low = 0LL; int64_t high = inf; while (low <= high) { int64_t mid = (low + high) / 2; int ord = order(mid); if (ord < k) low = mid + 1; else high = mid - 1; } printf("%I64d ", low); return 0; }