【51nod 1439】互斥對【容斥原理】

題意

給定一個長度爲 nn 的數組,a[1],a[2],...,a[n]a[1],a[2],...,a[n]。維護一個集合,一開始集合爲空。一共有 qq 次操作,每次操作給定一個下標 pospos,如果 a[pos]a[pos] 已經在集合中,則將 a[pos]a[pos] 從集合中刪除,否則將 a[pos]a[pos] 加入集合。注意,集合允許有重複的數字。(1n,q2105,1a[i]5105,1posn)(1\leq n,q\leq 2*10^5,1\leq a[i]\leq 5*10^5,1\leq pos\leq n)

問每次操作完之後,集合中互質的數字有多少對。

題目鏈接:linklink


思路

此題算是一道比較經典的容斥題,也可以用莫比烏斯函數來求解,但二者本質是一樣的。

首先比較容易想到的是,往集合中加一個數 a[pos]a[pos],則答案加上集合中與 a[pos]a[pos] 互質數的個數;從集合中刪除一個數 a[pos]a[pos],則答案減去集合中與 a[pos]a[pos] 互質數的個數,這種做法的複雜度是 O(nq)O(nq)

想要進一步優化複雜度,則需要降低求集合中與 a[pos]a[pos] 互質數個數的複雜度。我們將求互質轉爲求不互質,即:
 a[pos] = a[pos]  與 \ a[pos]\ 互質數的個數 = 集合大小-與 \ a[pos]\ 不互質數的個數
又因爲如果 xxyy 不互質,則必存在至少一個質數 cc,滿足 x%c==0x \% c==0y%c==0y\%c==0,因此我們假設 a[pos]a[pos] 的質因子有 p1p2p_1*p_2C[p1]C[p_1] 表示集合中有多少個數有 p1p_1 這個質因子,則可以根據容斥原理得到:
 a[pos] =C[p1]+C[p2]C[p1p2] 與\ a[pos]\ 不互質的個數 = C[p_1]+C[p_2]-C[p_1*p_2]
所有我們可以先求出每個數的質因子集合,然後用 dfsdfs 枚舉質因子子集,每當得到一個子集,則將子集中的數字全部乘起來,同時更新 CC 數字與容斥答案,具體細節見代碼。


代碼

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i = a; i <= b; i++)
typedef long long ll;
const int N = 5e5+1000;
using namespace std;

int n,q,a[N],vis[N],flag[N],C[N];
ll ans, tmp, cot;

vector<int> prime[N];

void init() {
	scanf("%d%d",&n,&q);
	rep(i,1,n) scanf("%d",&a[i]);
	for(int i = 2; i <= 5e5; i++){
		if(vis[i]) continue;
		for(int j = i; j <= 5e5; j += i) {
			vis[j] = 1;
			prime[j].push_back(i);
		}
	}
}

void dfs(int now, int num, int cnt, int mul, int op) {
	if(num == prime[now].size()) return;
	if(op == 1) {
		// 加入 now
		tmp += cnt*C[mul*prime[now][num]];
		C[mul*prime[now][num]]++;
	}
	else {
		// 減去 now
		C[mul*prime[now][num]]--;
		tmp += cnt*C[mul*prime[now][num]];
	}
	dfs(now, num + 1, cnt, mul, op);
	dfs(now, num + 1, cnt*(-1), mul*prime[now][num], op);
}

int main()
{
	init();
	while(q--) {
		int pos; scanf("%d",&pos);
		flag[pos] ^= 1;
		tmp = 0;
		if(flag[pos]) {
			dfs(a[pos], 0, 1, 1, 1);
			ans += cot - tmp;
			cot++;
		}
		else {
			dfs(a[pos], 0, 1, 1, -1), cot--;
			ans -= cot - tmp;
		}
		printf("%lld\n", ans);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章