LightOJ 1289 LCM from 1 to n

題目分析

這道題首先給人的感覺就是素數篩,但是空間明顯不夠,但是看看時間好像可以在4ms算完,於是就要優化空間了,然後學習了一個神奇的數據結構位圖。話說位圖看了半天其實就是在每個數組中用保存的2進制數來表示該數是否存在。因此我們設mod爲32,那麼對與每一個數i都可以的到一個商即i/mod,和一個餘數i%mod,並且這一對數是唯一的,因此我們就可以在vis下標爲i/mod存儲1<<(i%mod),於是直接素數篩解決就可以了,不過有以下小問題需要注意。比如這道題要mod2^32,這樣我們直接設一個數爲unsigned int即可,超出2^32後系統會直接mod。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define uint unsigned int
const int N = 1e8+5;
const int M = 6e6+10;
const int SHIFT = 5;
const int MASK = 0x1f;

int vis[(N>>SHIFT)+5];
uint sum[M];
int p[M];
int tot;

//利用位圖進行存儲,這樣可以縮小空間同時不增加時間
//將i存圖,存圖就是讓i/32得到的下標中存儲2的i/mod次方,直接位運算即可
inline void SetBit(int i){
    vis[i>>SHIFT] |= (1<<(i&MASK));
}
//判斷i是否已經被存過
inline int GetBit(int i){
    return vis[i>>SHIFT]&(1<<(i&MASK));
}

void isprime(){ //素數篩
    tot = 0;
    for(int i = 2; i < N; i++) if(!GetBit(i)){
        p[tot++] = i;
        for(int j = i+i; j < N; j += i)
            SetBit(j);
    }
}

uint solve(int n){
    int x = upper_bound(p, p+tot, n)-p-1;
    uint ans = sum[x];
    for(int i = 0; i < tot && p[i]*p[i] <= n; i++){
        int mul = p[i];
        int tmp = p[i]*p[i];
        while(tmp/mul == p[i] && tmp <= n){
            tmp *= p[i];
            mul *= p[i];
        }
        ans *= (mul/p[i]);  //注意這部分,因爲mul多了一個p[i],因此需要除去,不懂可以多想一下,很好理解。
    }
    return ans;
}

void init(){
    sum[0] = p[0];
    for(int i = 1; i < tot; i++)
        sum[i] = sum[i-1]*p[i];
}

int main(){
    isprime();
    init();
    int T, n;
    scanf("%d", &T);
    for(int kase = 1; kase <= T; kase++){
        scanf("%d", &n);
        printf("Case %d: %u\n", kase, solve(n));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章