ABC230G GCD Permutation 题解
LiuIR
·
2024-12-25 18:48:28
·
题解
题目大意
题目传送门
给定一个长为 n 的排列 p ,求有多少对 1\le i\le j\le n 满足 \gcd(i,j)\not=1\land \gcd(p_i,p_j)\not=1
## 题目分析
容易得到:
$$
\begin{aligned}
ans&=\sum_{i=1}^n\sum_{j=i}^n[\gcd(i,j)\not=1\land \gcd(p_i,p_j)\not=1]\\
&=\frac{1}{2}\left(\sum_{i=1}^n\sum_{j=1}^n[\gcd(i,j)\not=1\land \gcd(p_i,p_j)\not=1]+\sum_{i=1}^n[\gcd(i,i)\not=1\land \gcd(p_i,p_i)\not=1]\right)
\end{aligned}
$$
于是现在的答案转变为求出
$$
res=\sum_{i=1}^n\sum_{j=1}^n[\gcd(i,j)\not=1\land \gcd(p_i,p_j)\not=1]
$$
记
$$
\begin{aligned}
A&=\{(i,j)|[gcd(i,j)\not=1]\}\\
B&=\{(i,j)|[gcd(p_i,p_j)\not=1]\}\\
\end{aligned}
$$
那么有
$$
res=\left|A\cap B\right|=\left|U\right|-\left|\overline{A}\right|-\left|\overline{B}\right|+\left|\overline{A}\cap\overline{B}\right|
$$
$\left|U\right|$ 是显然的。于是只需求出 $\left|\overline{A}\right|,\left|\overline{B}\right|,\left|\overline{A}\cap\overline{B}\right|$。
### $\left|\overline{A}\right|
\begin{aligned}
\left|\overline{A}\right|&=\sum_{i=1}^n\sum_{j=1}^n[\gcd(i,j)=1]\\
&=\sum_{i=1}^n\sum_{j=1}^n\sum_{d|i,d|j}\mu(d)\\
&=\sum_{d=1}^n\mu(d)\left(\sum_{i=1}^n[d|i]\right)^2\\
&=\sum_{d=1}^n\mu(d)\left(\lfloor\frac{n}{d}\rfloor\right)^2
\end{aligned}
\left|\overline{B}\right|
先设 f(d)=\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}[\gcd(p_{id},p_{jd})=1] ,具体怎么求下文再讲。
那么有 \left|\overline{B}\right|=f(1) 。
\left|\overline{A}\cap\overline{B}\right|
\begin{aligned}
\left|\overline{A}\cap\overline{B}\right|&=\sum_{i=1}^n\sum_{j=1}^n[\gcd(i,j)=1\land\gcd(p_i,p_j)=1]\\
&=\sum_{i=1}^n\sum_{j=1}^n[gcd(p_i,p_j)=1]\sum_{d|i,d|j}\mu(d)\\
&=\sum_{d=1}^n\mu(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}[\gcd(p_{id},p_{jd})=1]\\
&=\sum_{d=1}^n\mu(d)f(d)
\end{aligned}
f(d)
\begin{aligned}
f(d)&=\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}[\gcd(p_{id},p_{jd})=1]\\
&=\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{t|p_{id},t|p_{jd}}\mu(t)\\
&=\sum_{t=1}^n\mu(t)\left(\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}[d|p_{id}]\right)^2
\end{aligned}
由于 id 的总数是 O(n\ln n) 的,所以可以想到暴力枚举每一个 id 。那么此时只会对 p_{id} 的因数产生贡献。
若记 buc_t=\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}[d|p_{id}] ,那么贡献就会从 \mu(t)buc_t^2 变成 \mu(t)(buc_t+1)^2 。拆开后可以得到贡献增加了 \mu(t)(2buc_t+1) 。
预处理出因数就可以动态维护答案了。时间复杂度 O(n\log n\max_{i=1}^nd(i)) 。
代码
主要代码如下:
signed main()
{
SetIO();
cin >> n;
Init(n);
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j += i)
factor[j].eb(i);
for (int d = 1; d <= n; d++)
{
for (int i = d; i <= n; i += d)
for (int t : factor[a[i]])
{
f[d] += mu[t] * (2 * buc[t] + 1);
buc[t]++;
}
for (int i = d; i <= n; i += d)
for (int t : factor[a[i]])
buc[t]--;
}
ans = 1ll * n * n;
for (int d = 1; d <= n; d++)
ans -= mu[d] * (n / d) * (n / d);
ans -= f[1];
for (int d = 1; d <= n; d++)
ans += f[d] * mu[d];
for (int i = 2; i <= n; i++)if (a[i] != 1)
ans++;
cout << ans / 2;
return 0;
}