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
#include
#include
#include
#include
#include
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;
}