题目
[CodeForces 547C] Mike and Foam
分析
设 c i c_i ci 表示 i i i 的个数,要求 i < j i < j i<j 比较麻烦,考虑求 t = ∑ i = 1 n ∑ j = 1 n [ gcd ( a i , a j ) = 1 ] t = \sum_{i = 1}^n\sum_{j = 1}^{n}[\gcd(a_i, a_j) = 1] t=i=1∑nj=1∑n[gcd(ai,aj)=1] 则答案为 t − c 1 2 \frac{t - c_1}{2} 2t−c1。设 m m m 是最大值: t = ∑ i = 1 n ∑ j = 1 n [ gcd ( a i , a j ) = 1 ] = ∑ d = 1 m μ ( d ) ( ∑ i = 1 ⌊ m d ⌋ c i ⋅ d ) 2 \begin{aligned} t = &\sum_{i = 1}^n\sum_{j = 1}^{n}[\gcd(a_i, a_j) = 1] \\ =& \sum_{d = 1}^m\mu(d) \left(\sum_{i = 1}^{\left\lfloor \frac{m}{d} \right\rfloor} {c_{i \cdot d}}\right)^2\end{aligned} t==i=1∑nj=1∑n[gcd(ai,aj)=1]d=1∑mμ(d)⎝⎜⎛i=1∑⌊dm⌋ci⋅d⎠⎟⎞2 令 f ( x ) = ∑ i = 1 ⌊ m x ⌋ c i ⋅ x f(x) = \sum\limits_{i = 1}^{\left\lfloor \frac{m}{x} \right\rfloor} {c_{i \cdot x}} f(x)=i=1∑⌊xm⌋ci⋅x,发现修改一个数涉及到要修改的 f f f 值是所有它的因数,枚举因数的时间复杂度是 O ( m ) O(\sqrt{m}) O(m),因此暴力修改即可。
最开始处理 f f f 的复杂度是 O ( ∑ i = 1 m m i ) = O ( m ln m ) O(\sum_{i = 1}^m\frac{m}{i}) = O(m \ln m) O(∑i=1mim)=O(mlnm),不会 T。
代码
#include <bits/stdc++.h>
typedef long long LL;
const int MAXN = 500000;
int N, M, Q;
int A[MAXN + 5];
LL Cnt[MAXN + 5], Num[MAXN + 5];
int Mu[MAXN + 5];
bool Vis[MAXN + 5];
std::vector<int> Primes;
void Init(int n) {
Mu[1] = 1;
for (int i = 2; i <= n; i++) {
if (!Vis[i])
Mu[i] = -1, Primes.push_back(i);
for (int j = 0; j < (int)Primes.size() && i * Primes[j] < n; j++) {
Vis[i * Primes[j]] = true;
if (i % Primes[j] == 0) {
Mu[i * Primes[j]] = 0;
break;
}
Mu[i * Primes[j]] = -Mu[i];
}
}
}
int main() {
Init(MAXN);
memset(Vis, 0, sizeof Vis);
scanf("%d%d", &N, &Q);
for (int i = 1; i <= N; i++)
scanf("%d", &A[i]), M = std::max(M, A[i]);
LL Ans = 0;
while (Q--) {
int pos; scanf("%d", &pos);
int dlt = Vis[pos] ? -1 : 1;
for (int i = 1; i * i <= A[pos]; i++) {
if (A[pos] % i) continue;
int j = A[pos] / i;
if (j <= M / i) {
Ans -= Num[i] * Num[i] * Mu[i];
Num[i] += dlt;
Ans += Num[i] * Num[i] * Mu[i];
}
if (i != j && i <= M / j) {
Ans -= Num[j] * Num[j] * Mu[j];
Num[j] += dlt;
Ans += Num[j] * Num[j] * Mu[j];
}
}
Cnt[A[pos]] += dlt;
Vis[pos] = !Vis[pos];
printf("%lld\n", (Ans - Cnt[1]) / 2);
}
return 0;
}