Link
BZOJ - https://www.lydsy.com/JudgeOnline/problem.php?id=5276
Codeforces - http://codeforces.com/contest/235/problem/E
Description
∑
i
=
1
A
∑
j
=
1
B
∑
k
=
1
C
d
(
i
j
k
)
m
o
d
  
2
30
\sum\limits_{i=1}^A\sum\limits_{j=1}^B\sum\limits_{k=1}^Cd(ijk)\mod{2^{30}}
i=1∑Aj=1∑Bk=1∑Cd(ijk)mod230
怎么没有背景小故事鸭
∑
i
=
1
A
∑
j
=
1
B
∑
k
=
1
C
d
(
i
j
k
)
=
∑
i
=
1
A
∑
j
=
1
B
∑
k
=
1
C
[
(
i
,
j
)
=
(
j
,
k
)
=
(
k
,
i
)
=
1
]
⌊
A
i
⌋
⌊
B
j
⌋
⌊
C
k
⌋
=
\begin{array}{rcl} \sum\limits_{i=1}^A\sum\limits_{j=1}^B\sum\limits_{k=1}^Cd(ijk)&=&\sum\limits_{i=1}^A\sum\limits_{j=1}^B\sum\limits_{k=1}^C[(i,j)=(j,k)=(k,i)=1]\lfloor\frac{A}{i}\rfloor\lfloor\frac{B}{j}\rfloor\lfloor\frac{C}{k}\rfloor\\ &=&\\ \end{array}
i=1∑Aj=1∑Bk=1∑Cd(ijk)==i=1∑Aj=1∑Bk=1∑C[(i,j)=(j,k)=(k,i)=1]⌊iA⌋⌊jB⌋⌊kC⌋
这个
[
(
i
,
j
)
=
(
j
,
k
)
=
(
k
,
i
)
=
1
]
[(i,j)=(j,k)=(k,i)=1]
[(i,j)=(j,k)=(k,i)=1] 有点骚啊,好像没办法化掉
多一个求和就多出了两个 gcd ,那少掉一个不就可以。。。
这种时候就要考虑万能的大力枚举了(
暴枚
i
i
i
∑
i
=
1
A
⌊
A
i
⌋
∑
j
=
1
B
∑
k
=
1
C
[
(
j
,
k
)
=
1
]
[
(
i
,
j
)
=
1
]
[
(
i
,
k
)
=
1
]
⌊
B
j
⌋
⌊
C
k
⌋
\sum\limits_{i=1}^A\lfloor\frac{A}{i}\rfloor\sum\limits_{j=1}^B\sum\limits_{k=1}^C[(j,k)=1][(i,j)=1][(i,k)=1]\lfloor\frac{B}{j}\rfloor\lfloor\frac{C}{k}\rfloor
i=1∑A⌊iA⌋j=1∑Bk=1∑C[(j,k)=1][(i,j)=1][(i,k)=1]⌊jB⌋⌊kC⌋
∑
i
=
1
A
⌊
A
i
⌋
∑
j
=
1
B
∑
k
=
1
C
[
(
j
,
k
)
=
1
]
[
(
i
,
j
k
)
=
1
]
⌊
B
j
⌋
⌊
C
k
⌋
\sum\limits_{i=1}^A\lfloor\frac{A}{i}\rfloor\sum\limits_{j=1}^B\sum\limits_{k=1}^C[(j,k)=1][(i,jk)=1]\lfloor\frac{B}{j}\rfloor\lfloor\frac{C}{k}\rfloor
i=1∑A⌊iA⌋j=1∑Bk=1∑C[(j,k)=1][(i,jk)=1]⌊jB⌋⌊kC⌋
∑
i
=
1
A
⌊
A
i
⌋
∑
j
=
1
B
∑
k
=
1
C
[
(
i
,
j
k
)
=
1
]
∑
d
∣
(
i
,
j
)
μ
(
d
)
⌊
B
j
⌋
⌊
C
k
⌋
\sum\limits_{i=1}^A\lfloor\frac{A}{i}\rfloor\sum\limits_{j=1}^B\sum\limits_{k=1}^C[(i,jk)=1]\sum\limits_{d|(i,j)}\mu(d)\lfloor\frac{B}{j}\rfloor\lfloor\frac{C}{k}\rfloor
i=1∑A⌊iA⌋j=1∑Bk=1∑C[(i,jk)=1]d∣(i,j)∑μ(d)⌊jB⌋⌊kC⌋
∑
i
=
1
A
⌊
A
i
⌋
∑
d
=
1
min
(
B
,
C
)
μ
(
d
)
∑
j
=
1
⌊
B
d
⌋
∑
k
=
1
⌊
C
d
⌋
[
(
i
,
d
2
j
k
)
=
1
]
j
k
\sum\limits_{i=1}^A\lfloor\frac{A}{i}\rfloor\sum\limits_{d=1}^{\min(B,C)}\mu(d)\sum\limits_{j=1}^{\left\lfloor\frac{B}{d}\right\rfloor}\sum\limits_{k=1}^{\left\lfloor\frac{C}{d}\right\rfloor}[(i,d^2jk)=1]jk
i=1∑A⌊iA⌋d=1∑min(B,C)μ(d)j=1∑⌊dB⌋k=1∑⌊dC⌋[(i,d2jk)=1]jk
∑
i
=
1
A
⌊
A
i
⌋
∑
d
=
1
min
(
B
,
C
)
μ
(
d
)
∑
j
=
1
⌊
B
d
⌋
[
(
i
,
d
j
)
=
1
]
⌊
B
d
j
⌋
∑
k
=
1
⌊
C
d
⌋
[
(
i
,
d
k
)
=
1
]
⌊
C
d
k
⌋
\sum\limits_{i=1}^A\lfloor\frac{A}{i}\rfloor\sum\limits_{d=1}^{\min(B,C)}\mu(d)\sum\limits_{j=1}^{\left\lfloor\frac{B}{d}\right\rfloor}[(i,dj)=1]\left\lfloor\frac{B}{dj}\right\rfloor\sum\limits_{k=1}^{\left\lfloor\frac{C}{d}\right\rfloor}[(i,dk)=1]\left\lfloor\frac{C}{dk}\right\rfloor
i=1∑A⌊iA⌋d=1∑min(B,C)μ(d)j=1∑⌊dB⌋[(i,dj)=1]⌊djB⌋k=1∑⌊dC⌋[(i,dk)=1]⌊dkC⌋
预处理
g
c
d
gcd
gcd 和
m
u
mu
mu 并且枚举
i
,
d
i,d
i,d
复杂度是
O
(
n
2
log
n
)
O(n^2\log n)
O(n2logn) 。枚举
i
i
i 和
d
d
d 是
O
(
n
2
)
O(n^2)
O(n2) 的,最后部分的复杂度是调和级数。
可以过 cf 但是并不能过 bzoj 。(如果你是超小常数选手请无视
那怎么办啊?
右转 [SDOI2018] 旧试题。
另一种做法
∑
i
=
1
A
∑
j
=
1
B
∑
k
=
1
C
d
(
i
j
k
)
\sum\limits_{i=1}^A\sum\limits_{j=1}^B\sum\limits_{k=1}^Cd(ijk)
i=1∑Aj=1∑Bk=1∑Cd(ijk)
仍然枚举
i
i
i 。考虑把后面两个合起来?
∑
i
=
1
A
∑
j
=
1
B
C
(
∑
u
=
1
B
∑
v
=
1
C
[
u
v
=
j
]
)
d
(
i
j
)
\sum\limits_{i=1}^A\sum\limits_{j=1}^{BC}\left(\sum\limits_{u=1}^B\sum\limits_{v=1}^C[uv=j]\right)d(ij)
i=1∑Aj=1∑BC(u=1∑Bv=1∑C[uv=j])d(ij)
显然可以
O
(
A
min
(
B
,
C
)
)
O(A\min(B,C))
O(Amin(B,C)) 预处理中间那个。设为
f
(
j
)
f(j)
f(j) 。
∑
j
=
1
B
C
f
(
j
)
∑
i
=
1
A
d
(
i
j
)
\sum\limits_{j=1}^{BC}f(j)\sum\limits_{i=1}^Ad(ij)
j=1∑BCf(j)i=1∑Ad(ij)
看起来有点丑啊,重写一下字母
∑
i
=
1
A
B
f
(
i
)
∑
j
=
1
C
d
(
i
j
)
\sum\limits_{i=1}^{AB}f(i)\sum\limits_{j=1}^Cd(ij)
i=1∑ABf(i)j=1∑Cd(ij)
大力套路一波
∑
i
=
1
A
B
f
(
i
)
∑
j
=
1
C
∑
u
∣
i
∑
v
∣
j
[
(
u
,
v
)
=
1
]
\sum\limits_{i=1}^{AB}f(i)\sum\limits_{j=1}^C\sum\limits_{u|i}\sum\limits_{v|j}[(u,v)=1]
i=1∑ABf(i)j=1∑Cu∣i∑v∣j∑[(u,v)=1]
∑
i
=
1
A
B
f
(
i
)
∑
j
=
1
C
∑
u
∣
i
∑
v
∣
j
∑
d
∣
(
u
,
v
)
μ
(
d
)
\sum\limits_{i=1}^{AB}f(i)\sum\limits_{j=1}^C\sum\limits_{u|i}\sum\limits_{v|j}\sum\limits_{d|(u,v)}\mu(d)
i=1∑ABf(i)j=1∑Cu∣i∑v∣j∑d∣(u,v)∑μ(d) 这可属实劲爆、、不对吧
回去。这里枚举约数显然不是这么暴力套路展开。
∑
i
=
1
A
B
f
(
i
)
∑
j
=
1
C
d
(
i
j
)
\sum\limits_{i=1}^{AB}f(i)\sum\limits_{j=1}^Cd(ij)
i=1∑ABf(i)j=1∑Cd(ij) 这个什么都看不出来
∑
i
=
1
A
B
f
(
i
)
∑
j
=
1
C
∑
u
∣
i
∑
v
∣
j
[
(
u
,
v
)
=
1
]
\sum\limits_{i=1}^{AB}f(i)\sum\limits_{j=1}^C\sum\limits_{u|i}\sum\limits_{v|j}[(u,v)=1]
i=1∑ABf(i)j=1∑Cu∣i∑v∣j∑[(u,v)=1] 有事可搞
∑
u
=
1
A
B
∑
v
=
1
C
[
(
u
,
v
)
=
1
]
⌊
C
v
⌋
∑
d
=
1
A
B
u
f
(
u
d
)
\sum\limits_{u=1}^{AB}\sum\limits_{v=1}^C[(u,v)=1]\left\lfloor\frac{C}{v}\right\rfloor\sum\limits_{d=1}^{\frac{AB}{u}}f(ud)
u=1∑ABv=1∑C[(u,v)=1]⌊vC⌋d=1∑uABf(ud)
把最后那个东西记为
g
(
u
)
g(u)
g(u) 。发现预处理要 O(n2ln n) 那就再见吧再见吧
剩下的推倒
PS:CF tutorial提到了一种dp的做法 复杂度。。。
O(n^2logn)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
const int MAXN = 5005;
const long long MOD = 1 << 30;
int A, B, C, D, E, F;
int Mu[MAXN], PrimeList[MAXN], Gcd[MAXN][MAXN];
bool NotPrime[MAXN];
int gcd(const int& a, const int& b)
{
if (Gcd[a][b]) return Gcd[a][b];
if (!b) return (Gcd[a][b] = Gcd[b][a] = a);
return Gcd[a][b] = Gcd[b][a] = gcd(b, a%b);
}
void Init()
{
NotPrime[0] = NotPrime[1] = 1; Mu[0] = 0, Mu[1] = 1;
for (register int t, i = 2; i <= E; ++i)
{
if (!NotPrime[i])
{
PrimeList[++PrimeList[0]] = i;
Mu[i] = -1;
}
for (register int j = 1; j <= PrimeList[0] && (t = i * PrimeList[j]) <= E; ++j)
{
NotPrime[t] = 1;
if (!(i % PrimeList[j])) { Mu[t] = 0; break;}
Mu[t] = -Mu[i];
}
}
for (register int i = 2; i <= A; ++i)
{
for (register int j = 2; j <= F; ++j)
{
if (!Gcd[i][j]) gcd(i, j);
}
}
}
long long Summy(const int& i, const int& N, const int& d)
{
register long long Ret = 0;
const int Lim = N / d;
for (register int dk = d, k = 1; k <= Lim; ++k, dk += d)
{
if (i==1 || (d==1&&k==1) || Gcd[i][dk]==1)
{
Ret += N / dk;
(Ret >= MOD) ? (Ret -= MOD) : 0;
}
}
return Ret;
}
int main()
{
scanf("%d%d%d", &A, &B, &C);
D = min(B, C);
E = max(max(A, B), C);
F = (D == B) ? C : B;
Init();
register long long Ans = 0, Tmp;
for (register int i = 1; i <= A; ++i)
{
Tmp = 0;
for (register int j = 1; j <= D; ++j)
{
Tmp += Summy(i, B, j) * Summy(i, C, j) % MOD * Mu[j];
}
Ans += Tmp * (A / i) % MOD;
if (Ans >= MOD) Ans -= MOD;
}
printf("%I64d", Ans);
return 0;
}