題目分析
這道題首先給人的感覺就是素數篩,但是空間明顯不夠,但是看看時間好像可以在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;
}