有 n (≤ 2×10⁵) 種啤酒,第 i 種濃度 aᵢ (≤ 5×10⁵)。初始集合為空。q (≤ 2×10⁵) 次操作:
x:若 aₓ 不在集合中則加入,否則移除。
每次操作後輸出:集合中互質數對個數(即 gcd(aᵢ, aⱼ) = 1 的無序對數)。
設當前集合大小為 S。新增元素 v 時,互質對增加量 = S - (與 v 不互質的元素數)。
移除元素 v 時,互質對減少量 = (S-1) - (與 v 不互質的其他元素數)。
關鍵子問題:快速查詢「集合中有多少數與 v 不互質」。
v ≤ 5×10⁵,質因子個數 ≤ 6(因 2×3×5×7×11×13×17 > 5×10⁵)。
設 v 的不同質因子為 p₁..pₖ。
與 v 不互質 ⇔ 能被至少一個 pᵢ 整除。
用容斥原理:對所有非空子集,計算集合中能被該子集乘積整除的數,奇加偶減。
維護 cnt[d] = 當前集合中能被 d 整除的元素個數(d 為無平方因子數,即質因子乘積)。
新增 v:枚舉其質因子子集,乘積 d,cnt[d]++。
移除 v:同理 cnt[d]--。
查詢不互質數:枚舉子集,奇加偶減 cnt[d]。
1 與任何數互質。單獨維護 one = 集合中 1 的個數。
新增 1:互質對增加 S(與所有現有元素互質)。
移除 1:互質對減少 S-1。
vector primes[500001]; // 預處理每數的質因子
int cnt[500001] = {0};
ll ans = 0;
int one = 0;
unordered_set S; // 或 bool inSet[]
void add(int v) {
if (v == 1) { ans += S.size(); one++; S.insert(1); return; }
int notCoprime = 0;
vector& pf = primes[v];
int k = pf.size();
for (int mask = 1; mask < (1<
CF 547C 是質因子分解 + 容斥原理 + 動態計數器的完美結合。關鍵點:
1. 數值 ≤ 5×10⁵ ⇒ 質因子 ≤ 6 ⇒ 子集枚舉極快
2. 維護 cnt[d] 實現 O(1) 查詢「能被 d 整除的個數」
3. 互質對增量 = 集合大小 - 不互質數
4. 1 的特殊處理
此模板廣泛適用於「動態集合互質查詢、倍數查詢」類問題。