https://codeforces.com/contest/547/problem/C
题目描述
原题来自:Codeforces#547 Div1 C.Mike and Foam
翻译来源:牛客网
M i k e Mike Mike 是 R i c o Rico Rico 酒吧的调酒师。在 R i c o Rico Rico 酒吧,他们将啤酒杯放在一个特殊的架子上。在 R i c o Rico Rico 酒吧,有 n n n 种啤酒编号从 1 1 1 到 n n n 。第 i i i 瓶啤酒上面有 a i a_{i} ai 毫升的泡沫。
M a x i m Maxim Maxim 是 M i k e Mike Mike 的老板。今天他让 M i k e Mike Mike 回答 q q q 个查询。最初架子是空的。在每个操作中, M a x i m Maxim Maxim 给他一个编号XX。如果编号为 X X X 的啤酒已经在架子上,那么 M i k e Mike Mike 应该从架子上取下它,否则他应该把它放在架子上。
每次询问后, M i k e Mike Mike 应该告诉他架子的分数。他们认为货架的分数是满足 i < j i<j i<j 并且 g c d ( a i , a j ) = 1 gcd(a_{i},a_{j})=1 gcd(ai,aj)=1 的数对 ( i , j ) (i,j) (i,j) 的个数。
M i k e Mike Mike 现在很累。所以他请你帮他处理这些操作。
Solution
(本题容斥的应用真的很妙)
反面考虑,
a
n
s
=
ans =
ans= 当前柜台上的个数
−
a
[
x
]
- a[x]
−a[x] 与柜台上的数不互质的个数
我们用一个
s
u
m
sum
sum 数组来维护当前柜台上的数的因数出现的次数,也就是维护
i
i
i 是当前柜台上多少个数的因子,这个值存在
s
u
m
[
i
]
sum[i]
sum[i] 中。
a
[
x
]
a[x]
a[x] 与柜台上的数不互质的个数 =
a
[
x
]
a[x]
a[x] 是柜台上的一个质因数的倍数的个数 -
a
[
x
]
a[x]
a[x] 是柜台上的两个质因数的倍数的个数
+
+
+
.
.
.
...
...
+
+
+
(
−
1
)
i
∗
a
[
x
]
(-1)^i*a[x]
(−1)i∗a[x] 是柜台上的
i
i
i 个质因数的倍数的个数
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 500010;
#define int long long
int primes[N], vis[N], cnt;
int a[N];
bool used[N];
int sum[N];
signed main(){
for (int i=2; i<=500000; i++){
if(!vis[i]) vis[i]=i, primes[++cnt] = i;
for (int j=1; j<=cnt&&i*primes[j]<=500000; j++){
vis[i*primes[j]] = primes[j];
if(i%primes[j]==0) break;
}
}
int n, q;
cin >> n >> q;
for (int i=1; i<=n; i++) cin >> a[i];
int ans = 0;
while (q--){
int x;
cin >> x;
if(!used[x]){
vector<int> v;
int cur = a[x];
while (cur > 1)
v.push_back(vis[cur]), cur /= vis[cur];
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
int m = (int)v.size();
for (int i=0; i<1<<m; i++){
int tmp = 1;
int t = 1;
for (int j=0; j<m; j++) if(i>>j&1){
t *= v[j];
tmp = -tmp;
}
ans += tmp * sum[t];
sum[t] ++;
}
cout << ans << '\n';
}else{
vector<int> v;
int cur = a[x];
while (cur > 1)
v.push_back(vis[cur]), cur /= vis[cur];
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
int m = (int)v.size();
for (int i=0; i<1<<m; i++){
int tmp = 1;
int t = 1;
for (int j=0; j<m; j++) if(i>>j&1){
t *= v[j];
tmp = -tmp;
}
sum[t] --;
ans -= tmp * sum[t];
}
cout << ans << '\n';
}
used[x] = !used[x];
}
return 0;
}