[数学基础] 11 丑数筛

丑数筛

给定一个质数集合S={p1,p2,..,pk},只由这些质数相乘得到的数我们成为丑数(Humble/Ugly Numbers)。习惯上,我们认为第一个丑数是1,但是也可能不是,所以看清题意。记第n大 的丑数为h[n]

无论哪种方法,这个丑数实际上都是可能非常大的,建议直接上__int128!!

第一种筛法,也是最常用的,就是搞一个优先队列,每次提出来优先队列中最小的数,注意去重

这种方法的时间复杂度是O((n×k)log(n×k))

#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+双指针,复杂度O(n×k)注意,这里的下标是从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]一定从这些数中产生
posted @   跳岩  阅读(58)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示