[BZOJ5276] Skyfall & [CF235E] Number Challenge [莫比乌斯反演]

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=1Aj=1Bk=1Cd(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=1Aj=1Bk=1Cd(ijk)==i=1Aj=1Bk=1C[(i,j)=(j,k)=(k,i)=1]iAjBkC
这个 [ ( 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=1AiAj=1Bk=1C[(j,k)=1][(i,j)=1][(i,k)=1]jBkC
∑ 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=1AiAj=1Bk=1C[(j,k)=1][(i,jk)=1]jBkC
∑ 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=1AiAj=1Bk=1C[(i,jk)=1]d(i,j)μ(d)jBkC
∑ 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=1AiAd=1min(B,C)μ(d)j=1dBk=1dC[(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=1AiAd=1min(B,C)μ(d)j=1dB[(i,dj)=1]djBk=1dC[(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=1Aj=1Bk=1Cd(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=1Aj=1BC(u=1Bv=1C[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=1BCf(j)i=1Ad(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=1ABf(i)j=1Cd(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=1ABf(i)j=1Cuivj[(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=1ABf(i)j=1Cuivjd(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=1ABf(i)j=1Cd(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=1ABf(i)j=1Cuivj[(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=1ABv=1C[(u,v)=1]vCd=1uABf(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;
}

你可能感兴趣的:(莫比乌斯反演,数论)