維護一個初始為 1..n 的數列 A,支持兩種操作(共 M ≤ 1000 次):
求與 p 互質的數之和,等價於區間總和 減去 與 p 不互質(即與 p 有公約數)的數之和。後者可用容斥原理計算:設 p 的質因子為 prime[1..k],則與 p 不互質的數即為能被至少一個質因子整除的數。容斥公式為:
Sum = Σ (-1)^(cnt+1) * (倍數之和),其中遍歷所有非空質因子子集,cnt 為子集大小,倍數之和為等差數列求和。
solve(n, p)LL solve(int n, int p) { // 求 [1, n] 中與 p 不互質的數之和
LL ans = 0;
int sz = prime[p].size();
int subsets = (1 << sz);
for (int mask = 1; mask < subsets; mask++) {
LL lcm = 1, cnt = 0;
for (int i = 0; i < sz; i++) if (mask >> i & 1) {
lcm *= prime[p][i];
cnt++;
if (lcm > n) break;
}
if (lcm > n) continue;
LL num = n / lcm;
LL sum = (lcm + lcm * num) * num / 2; // 等差數列和
if (cnt & 1) ans += sum; else ans -= sum;
}
return ans;
}
修改次數較少(≤ M),可將所有修改記錄在 map 中(key=位置, value=新值)。查詢時:
solve 算出原始數列在 [l, r] 中與 p 不互質的和 ans。ms 中所有修改記錄,若位置落在 [l, r] 內,則調整 ans:
ans += old_val - new_val(因總和變了)。(su[r] - su[l-1]) - ans,其中 su[i] 為 1..i 的前綴和。vector prime[maxn] 存儲每個數的質因子。map 自動按位置排序,遍歷方便。long long 防溢出。本題巧妙結合了數論(容斥原理)與離線處理修改的技巧。利用修改操作較少的特性,將動態問題轉化為靜態查詢加少量修正,避免了複雜的數據結構,代碼簡潔高效。