查詢區間 [n, m] 內所有整數的素因子個數的最大公約數(GCD)。
freq[8](下標 1~7 為素因子個數出現次數,0 或 1)freq[k] = left.freq[k] + right.freq[k]sum[8]short 存儲(計數 ≤ 區間長度 ≤ 105,short 足夠),節省記憶體const int MAXN = 1e6;
int prime[MAXN], phi[MAXN], cnt_pf[MAXN]; // cnt_pf[i] = i的素因子個數
bool vis[MAXN];
void linear_sieve() {
for (int i = 2; i < MAXN; ++i) {
if (!vis[i]) { prime[++prime[0]] = i; cnt_pf[i] = 1; }
for (int j = 1; j <= prime[0] && i * prime[j] < MAXN; ++j) {
vis[i * prime[j]] = true;
if (i % prime[j] == 0) {
cnt_pf[i * prime[j]] = cnt_pf[i] + 1;
break;
} else {
cnt_pf[i * prime[j]] = cnt_pf[i] + 1;
}
}
}
}
short tree[MAXN*4][8]; // [節點][素因子個數] = 計數
void build(int node, int l, int r) {
if (l == r) {
tree[node][cnt_pf[l]] = 1;
return;
}
int mid = (l + r) >> 1;
build(node<<1, l, mid);
build(node<<1|1, mid+1, r);
for (int k = 1; k <= 7; ++k)
tree[node][k] = tree[node<<1][k] + tree[node<<1|1][k];
}
void query(int node, int l, int r, int ql, int qr, short *res) {
if (ql <= l && r <= qr) {
for (int k = 1; k <= 7; ++k) res[k] += tree[node][k];
return;
}
int mid = (l + r) >> 1;
if (ql <= mid) query(node<<1, l, mid, ql, qr, res);
if (qr > mid) query(node<<1|1, mid+1, r, ql, qr, res);
}
short sum[8] = {0};
query(1, 1, MAXN, n, m, sum);
int ans = 0;
for (int i = 1; i <= 7; ++i)
if (sum[i])
for (int j = i; j <= 7; ++j)
if (sum[j])
ans = max(ans, gcd(i, j));
short 而非 int 存計數,內存減半本題巧妙利用「素因子個數 ≤ 7」這一數論性質,將問題轉化為區間頻次統計 + 小範圍枚舉 GCD。線段樹維護 7 維頻次向量,查詢後 O(7²) 枚舉即可得答案,體現了數論與數據結構結合的典型思路。