[数学基础] 11 丑数筛
丑数筛
给定一个质数集合,只由这些质数相乘得到的数我们成为丑数(Humble/Ugly Numbers)。习惯上,我们认为第一个丑数是1,但是也可能不是,所以看清题意。记第大 的丑数为。
无论哪种方法,这个丑数实际上都是可能非常大的,建议直接上__int128!!
第一种筛法,也是最常用的,就是搞一个优先队列,每次提出来优先队列中最小的数,注意去重。
这种方法的时间复杂度是
#define ll __int128
const ll INF = 9e37, N = 5e4 + 5;
ll h[N], p[3] = {2, 3, 5}, cnt[3];
priority_queue<ll, vector<ll>, greater<ll> > pq;
void Humble(int n){
pq.push(1);
ll last = 1;
for (int i=1;i<=n;++i){
for (int j=0;j<3;++j){
pq.push(last * p[j]);
}
last = pq.top();
while (!pq.empty() && last == pq.top()) pq.pop();
h[i] = last;
}
}
第二种线性筛法,相当于做了一个DP+双指针,复杂度。注意,这里的下标是从0开始的,并且,INF要足够足够大!!!!
(嗯?我这么大一个代码怎么没贴上来 赶紧亡羊补牢ing)
ll h[N], p[3] = {2, 3, 5}, cnt[3];
void Humble(int n){
h[0] = 1; // 下标0的地方是第一个数
for (int i=1;i<=n;++i){
h[i] = INF;
for (int j=0;j<3;++j){
while (p[j] * h[cnt[j]] <= h[i - 1]) cnt[j]++;
if (p[j] * h[cnt[j]] < h[i]){
h[i] = p[j] * h[cnt[j]];
}
}
}
}
// cnt[j]记录的是当前乘的最后一个质因子是p[j]的, 最小的那个数的下标
// h[i]一定从这些数中产生
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通