乱搞。
Description
若一个大于 $1$ 的整数 $M$ 的质因数分解有 $k$ 项,其最大的质因子为 $a_k$,并且满足 ${a_k}^k \leq N$, $a_k<128$,我们就称整数 $M$ 为 $N$-伪光滑数。
现在给出 $N$,求所有整数中,第 $K$ 大的 $N$-伪光滑数。
Solution
Sol. 1
在堆中插入最大素因子为每个素数的四元组$(v, p, fir, sec)$, 分别是当前数值, 最小素数编号, 最小素数指数, 次小素数指数.
每次堆中取最大值, 有两种扩展, 把一个次小素因子换成最小素因子/把一个最小素因子换成更小的下一个素因子.
可以证明这样能不重不漏地遍历所有数.
取走$k - 1$次即可. 再取堆顶就是答案了.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n; int k;
struct node { ll cur; int pr, fir, sec; inline bool operator<(const node &rhs) const { return cur < rhs.cur; } }; priority_queue<node> q;
int npr[150], cnt; ll pr[50]; void euler() { for (int i = 2; i < 128; ++i) { if (!npr[i]) pr[++cnt] = i; for (int j = 1; j <= cnt && i * pr[j] < 128; ++j) { npr[i * pr[j]] = 1; if (!(i % pr[j])) break; } } }
int main() { scanf("%lld%d", &n, &k); euler(); pr[0] = 1; node y; for (int i = 1; i <= 31; ++i) { ll pw = 1; int j = 0; for (; pw <= n / pr[i]; j++, pw *= pr[i]); node x; x.cur = pw; x.pr = i; x.fir = j - 1; x.sec = 0; q.push(x); } while (--k) { node x = q.top(); q.pop(); if (x.pr) { ll tmp = x.cur / pr[x.pr] * pr[x.pr - 1]; y.cur = tmp; y.pr = x.pr - 1; y.fir = 1; y.sec = x.fir - 1; q.push(y); } if (x.sec) { ll tmp = x.cur / pr[x.pr + 1] * pr[x.pr]; y.cur = tmp; y.pr = x.pr; y.fir = x.fir + 1; y.sec = x.sec - 1; q.push(y); } } y = q.top(); printf("%lld",y.cur); return 0; }
|
Sol. 2
是一个DP做法, 大概就是维护一个最大素因子为$i$, 有$k$个素因子的全体元素组成的集合, 转移支持集合乘, 集合取并, 集合最大值.
可持久化可并堆.
然而懒得写了.