hihocoder #1867 : GCD

给定一个排列 $a_1 \sim a_n$,其中 $1 \le n \le 2 \times 10^5$,求:

$$
\sum_{i=1}^{n}\sum_{j=i}^{n}[i \perp j] [a_i \perp a_j]
$$

发现这个 $j$ 的枚举不是从 $1$ 开始的,有些不爽,不妨看看能换成啥:

$$
\begin{aligned}
&\sum_{i=1}^{n}\sum_{j=1}^{n}[i \perp j][a_i \perp a_j] \\
=&[a_1=1]+2\sum_{i=1}^{n}\sum_{j=i+1}^{n}[i \perp j][a_i \perp a_j] \\
=&[a_1=1]-2[a_1=1]+2\sum_{i=1}^{n}\sum_{j=i}^{n}[i \perp j][a_i \perp a_j] \\
\end{aligned}
$$

也就是说:

$$
\sum_{i=1}^{n}\sum_{j=i}^{n}[i \perp j] [a_i \perp a_j]=\frac{[a_1=1]+\sum_{i=1}^{n}\sum_{j=1}^{n}[i \perp j][a_i \perp a_j]}{2}
$$

于是只需要关心 $j$ 从 $1$ 开始的那个式子就行了,这样就很好做了

设:

$$
F(d)=\sum_{i=1}^{n}\sum_{j=1}^{n}[d \mid i][d \mid j] [a_i \perp a_j]
$$

那么有:

$$
f(d)=\sum_{i=1}^{n}\sum_{j=1}^{n}[\gcd(i,j)=d][a_i \perp a_j]=(F \times \mu)(d)
$$

答案就是 $f(1)$ 了

考虑如何计算 $F(d)$,一个比较显然的思路就是:

$$
\begin{aligned}
F(d)=&\sum_{i=1}^{n}\sum_{j=1}^{n}[d \mid i][d \mid j] [a_i \perp a_j] \\
=&\sum_{t=1}^{n}\mu(t) \left(\sum_{i=1}^{n} [d \mid i] [t \mid a_i] \right)^2
\end{aligned}
$$

在枚举 $d$ 的时候,可以顺便把 $d$ 的所有倍数位置的 $a_i$ 都搞出来,然后放到一个 $g$ 数组中,其中 $g_x=\sum_{i=1}^{n} [d \mid i][x \mid a_i]$,这个可以直接枚举 $a_i$ 的约数后更新

这样一来计算 $F(d)$ 的时候只需要枚举所有 $d$ 的倍数的约数的并集就行了

不妨分析一下这种暴力的时间复杂度:

首先每一个 $a_i$ 会在 $i$ 的某个约数的时候被枚举到,之后还会枚举 $a_i$ 的约数,因此这部分的时间复杂度是 $O(\sum_{i=1}^{n}\sigma_0^2(i))$,经打表计算,在 $n =2 \times 10^5$ 的时候大概是 $10^7$ 左右的级别

至于其它地方的时间复杂度,都小于这个时间复杂度,因此总的时间复杂度就是 $O(\sum_{i=1}^{n}\sigma_0^2(i))$ 左右了

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 2e5 + 10;
 5 vector<int> g[N];
 6 ll ans, f[N], F[N], cnt[N];
 7 int n, mu[N], pri[N], tot, vis[N], a[N], fafa[N];
 8 
 9 int main() {
10     scanf("%d", &n);
11     for(int i = 1 ; i <= n ; ++ i) scanf("%d", &a[i]);
12     
13     mu[1] = 1;
14     for(int i = 2 ; i <= n ; ++ i) {
15         if(!vis[i]) {
16             mu[i] = -1;
17             pri[++ tot] = i;
18         }
19         for(int j = 1 ; j <= tot && i * pri[j] <= n ; ++ j) {
20             vis[i * pri[j]] = 1;
21             if(i % pri[j] == 0) break;
22             mu[i * pri[j]] = -mu[i];
23         }
24     }
25     
26     for(int i = 1 ; i <= n ; ++ i)
27         for(int j = i ; j <= n ; j += i)
28             g[j].push_back(i);
29     
30     for(int d = 1 ; d <= n ; ++ d) {
31         for(int i = d ; i <= n ; i += d) {
32             for(int j = 0 ; j < g[a[i]].size() ; ++ j) {
33                 ++ cnt[g[a[i]][j]];
34             }
35         }
36         
37         int T = ++ fafa[0];
38         for(int i = d ; i <= n ; i += d) {
39             for(int j = 0 ; j < g[a[i]].size() ; ++ j) {
40                 int x = g[a[i]][j];
41                 if(fafa[x] == T) continue;
42                 fafa[x] = T;
43                 f[d] += mu[x] * cnt[x] * cnt[x];
44                 cnt[x] = 0;
45             }
46         }
47     }
48     
49 //    for(int i = 1 ; i <= n ; ++ i)
50 //        for(int j = i ; j <= n ; j += i)
51 //            F[i] += f[j] * mu[j / i];
52 //    ans = (F[1] + (a[1] == 1)) / 2;
53     
54     for(int i = 1 ; i <= n ; ++ i)
55         ans += f[i] * mu[i];
56     ans = (ans + (a[1] == 1)) / 2;
57     printf("%lld\n", ans);
58 }
hihocoder #1867 : GCD

 

posted @ 2018-12-17 20:59 KingSann 阅读(...) 评论(...)  编辑 收藏