Codeforces 235E Number Challenge

这题是「『SDOI2018』旧试题」的弱化版。
等我搞懂三元环计数做法再去做那题吧。

\[\newcommand\ffrac[2]{\genfrac\lfloor\rfloor{}{}{ #1 }{ #2 }} \begin{align*} & \sum\limits_{i=1}^A\sum\limits_{j=1}^B\sum\limits_{k=1}^C d(ijk) \\ = & \sum\limits_{i=1}^A\sum\limits_{j=1}^B\sum\limits_{k=1}^C\sum\limits_{x|i}\sum\limits_{y|j}\sum\limits_{z|k} [\gcd(x,y)=1][\gcd(x,z)=1][\gcd(y,z)=1] \\ = & \sum\limits_{x=1}^A\sum\limits_{y=1}^B\sum\limits_{z=1}^C\ffrac Ax\ffrac By\ffrac Cz [\gcd(x,y)=1][\gcd(x,z)=1][\gcd(y,z)=1] \\ = & \sum\limits_{x=1}^A\sum\limits_{y=1}^B\sum\limits_{k=1}^C\ffrac Ax\ffrac By\ffrac Cz [\gcd(x,z)=1][\gcd(y,z)=1]\sum\limits_{d|\gcd(x,y)}\mu(d) \\ = & \sum\limits_{d=1}^{\min(A,B)}\mu(d)\sum\limits_{x=1}^{\ffrac Ad}\ffrac A{dx}\sum\limits_{y=1}^{\ffrac Bd} \ffrac B{dy}\sum\limits_{z=1}^C \ffrac Cz[\gcd(dx,z)=1][\gcd(dy,z)=1] \\ = & \sum\limits_{d=1}^{\min(A,B)}\mu(d)\sum\limits_{x=1}^{\ffrac Ad}\ffrac A{dx}\sum\limits_{y=1}^{\ffrac Bd} \ffrac B{dy}\sum\limits_{z=1}^C \ffrac Cz[\gcd(x,z)=1][\gcd(y,z)=1][\gcd(d,z)=1] \\ = & \sum\limits_{z=1}^C\ffrac Cz\sum\limits_{d=1}^{\min(A,B)}[\gcd(d,z)=1]\mu(d)\sum\limits_{x=1}^{\ffrac Ad}[\gcd(x,z)=1]\ffrac A{dx}\sum\limits_{y=1}^{\ffrac Bd}[\gcd(y,z)=1]\ffrac B{dy} \end{align*}\]

然后暴力算。
\(n = \max(A,B,C)\),复杂度是 \(O(n^2 \log n)\) 左右(反正三个都同阶随便把 \(n\) 换成一个都行)。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#pragma GCC optimize (3)
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 5e3;
int A,B,C;
int vis[N + 5],cnt,prime[N + 5],mu[N + 5];
int ans;
int main()
{
mu[1] = 1;
for(register int i = 2;i <= N;++i)
{
if(!vis[i])
mu[prime[++cnt] = i] = -1;
for(register int j = 1;j <= cnt && i * prime[j] <= N;++j)
{
vis[i * prime[j]] = 1;
if(!(i % prime[j]))
break;
else
mu[i * prime[j]] = -mu[i];
}
}
scanf("%d%d%d",&A,&B,&C);
for(register int i = 1,s;i <= C;++i)
{
s = 0;
for(register int j = 1,s1,s2;j <= A && j <= B;++j)
if(__gcd(i,j) == 1 && mu[j])
{
s1 = 0,s2 = 0;
for(register int k = j,l = 1;k <= A || k <= B;k += j,++l)
__gcd(i,l) == 1 && (s1 += (A / k),s2 += (B / k));
s += s1 * s2 * mu[j];
}
ans += s * (C / i);
}
printf("%d\n",ans & ((1 << 30) - 1));
}