[数学基础] 11 丑数筛

丑数筛

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

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

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

这种方法的时间复杂度是\(O((n\times k)\log (n\times 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\times 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 @ 2022-09-08 20:00  跳岩  阅读(47)  评论(0编辑  收藏  举报