判定整數 N (2 ≤ N ≤ 10¹⁸) 是否為無平方因子數(即不被除 1 外的任何完全平方數整除)。T ≤ 20 組測試。
若 N 有平方因子 p²,則 p ≤ √N ≤ 10⁹。但直接試除到 10⁹ 太慢。關鍵優化:
若 N 除盡所有 ≤ 10⁶ 的質數後餘數 > 1,則該餘數要么是質數,要么是兩個質數乘積(因若有三個質因子,最小乘積 > 10¹⁸)。故只需:
// 1. 線性/埃氏篩生成質數表
// 2. 對每個測試數 N:
ok = true
for p in primes:
if p*p > N: break
cnt = 0
while N % p == 0:
N /= p; cnt++
if cnt >= 2: ok = false; break
if not ok: break
if ok and N > 1:
x = (long long)sqrt(N)
if x*x == N: ok = false // 剩餘部分是平方數
output ok ? "Yes" : "No"
使用 vis[j]=1 標記合數,m = sqrt(n) 為篩選上限。10⁶ 篩選極快(<10ms)。
x = (long long)sqrt((double)N),雙精度浮點數 53 位尾數足夠精確表示 10¹⁸ 內整數開方。
#include <cstdio> #include <cstring> #include <cmath>
const int MAXN = 80000+10;
const int N = 1000000;
int prime[MAXN], vis[N];
__int64 N;
int pos;
int init() {
int c = 0, m = sqrt(N + 0.5);
memset(vis, 0, sizeof(vis));
for (int i = 2; i <= m; i++)
if (!vis[i])
for (int j = i*i; j <= N; j += i) vis[j] = 1;
for (int i = 2; i <= N; i++)
if (!vis[i]) prime[c++] = i;
return c;
}
int judge() {
for (int i = 0; i < pos; i++) {
while (N % prime[i] == 0) {
N /= prime[i];
if (N % prime[i] == 0) return 0;
}
}
return 1;
}
int main() {
pos = init();
int t, cas = 1;
scanf("%d", &t);
while (t--) {
__int64 x;
int ok = 1;
scanf("%I64d", &N);
if (!judge()) ok = 0;
if (N > 1000000) {
x = (int)sqrt((double)N);
if (x * x == N) ok = 0;
}
printf("Case %d: %s\n", cas++, ok ? "Yes" : "No");
}
return 0;
}
本題展示了大數因數分解的經典策略:小質數試除 + 大餘數特殊性質判斷。利用「N ≤ 10¹⁸ 除盡小質數後餘數最多有兩個質因子」的數學結構,將問題降維到可行範圍。