[BZOJ5332] [SDOI2018] 旧试题 & [BZOJ5276] Skyfall [莫比乌斯反演][三元环计数][std::vector][Cache Miss]

Link
Luogu - https://www.luogu.org/problemnew/show/P4619
BZOJ - https://www.lydsy.com/JudgeOnline/problem.php?id=5332


Description
T T T 组询问。每一组给出 1 ≤ A , B , C ≤ 1 0 5 1\le A,B,C\le10^5 1A,B,C105 求:
∑ i = 1 A ∑ j = 1 B ∑ k = 1 C d ( i j k ) m o d    1 0 9 + 7 \sum\limits_{i=1}^A\sum\limits_{j=1}^B\sum\limits_{k=1}^Cd(ijk)\mod{10^9+7} i=1Aj=1Bk=1Cd(ijk)mod109+7
满足 1 ≤ ∑ max ⁡ ( A , B , C ) ≤ 2 × 1 0 5 1\le\sum\max(A,B,C)\le2\times10^5 1max(A,B,C)2×105


∑ i = 1 A ∑ j = 1 B ∑ k = 1 C d ( i j k ) = ∑ i = 1 A ∑ j = 1 B ∑ k = 1 C [ ( i , j ) = 1 ] [ ( j , k ) = 1 ] [ ( k , i ) = 1 ] ⌊ A i ⌋ ⌊ B j ⌋ ⌊ C k ⌋ = ∑ i = 1 A ∑ j = 1 B ∑ k = 1 C ∑ a ∣ ( i , j ) μ ( a ) ∑ b ∣ ( j , k ) μ ( b ) ∑ c ∣ ( k , i ) μ ( c ) ⌊ 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)=1][(j,k)=1][(k,i)=1]\lfloor\frac{A}{i}\rfloor\lfloor\frac{B}{j}\rfloor\lfloor\frac{C}{k}\rfloor\\ &=&\sum\limits_{i=1}^A\sum\limits_{j=1}^B\sum\limits_{k=1}^C\sum\limits_{a|(i,j)}\mu(a)\sum\limits_{b|(j,k)}\mu(b)\sum\limits_{c|(k,i)}\mu(c)\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)=1][(j,k)=1][(k,i)=1]iAjBkCi=1Aj=1Bk=1Ca(i,j)μ(a)b(j,k)μ(b)c(k,i)μ(c)iAjBkC
但是这个时候你不好继续按照 Number Challenge 的方法推,
而且上面那条式子你也不好化开。那怎么办呢?
回退一层
∑ i = 1 A ∑ j = 1 B ∑ k = 1 C [ ( i , j ) = 1 ] [ ( j , k ) = 1 ] [ ( k , i ) = 1 ] ⌊ A i ⌋ ⌊ B j ⌋ ⌊ C k ⌋ \sum\limits_{i=1}^A\sum\limits_{j=1}^B\sum\limits_{k=1}^C[(i,j)=1][(j,k)=1][(k,i)=1]\left\lfloor\frac{A}{i}\right\rfloor\left\lfloor\frac{B}{j}\right\rfloor\left\lfloor\frac{C}{k}\right\rfloor i=1Aj=1Bk=1C[(i,j)=1][(j,k)=1][(k,i)=1]iAjBkC
你康到了什么?
实际上在推的时候就应该注意到的。 ( i , j ) ( j , k ) ( k , i ) (i,j)(j,k)(k,i) (i,j)(j,k)(k,i) 显然是一个三元环的形式
我们把互质的数两两连边,然后做三元环计数,每个三元环 ( i , j , k ) (i,j,k) (i,j,k) 的贡献是
( ⌊ A i ⌋ + ⌊ B i ⌋ + ⌊ C i ⌋ ) + ( ⌊ A j ⌋ + ⌊ B j ⌋ + ⌊ C j ⌋ ) + ( ⌊ A k ⌋ + ⌊ B k ⌋ + ⌊ C k ⌋ ) \left(\left\lfloor\frac{A}{i}\right\rfloor+\left\lfloor\frac{B}{i}\right\rfloor+\left\lfloor\frac{C}{i}\right\rfloor\right)+\left(\left\lfloor\frac{A}{j}\right\rfloor+\left\lfloor\frac{B}{j}\right\rfloor+\left\lfloor\frac{C}{j}\right\rfloor\right)+\left(\left\lfloor\frac{A}{k}\right\rfloor+\left\lfloor\frac{B}{k}\right\rfloor+\left\lfloor\frac{C}{k}\right\rfloor\right) (iA+iB+iC)+(jA+jB+jC)+(kA+kB+kC)
但是问题就来了:数最多有 2 × 1 0 5 2\times10^5 2×105 个,把互质的数两两连边的话就有好多好多个边
好多个边边
是吗
真的吗
复杂度的问题不能傻逼估计 你想想啊
n ( n − 1 ) 2 ln ⁡ 2 n \frac{n(n-1)}{2\ln^2 n} 2ln2nn(n1)
震 惊 好大啊 完了 那还真的跑卜过去
那怎么办啊?
说明我们这个力度不够 要加大力度
搞成什么呢 反演啊 搞个约数出来啊 d 2 ( n ) d^2(n) d2(n) 总没有问题吧 能 ω 2 ( n ) \omega^2(n) ω2(n) 就更美滋滋啦
不要放弃治疗 结果还是得硬化嘛
∑ i = 1 A ∑ j = 1 B ∑ k = 1 C [ ( i , j ) = 1 ] [ ( j , k ) = 1 ] [ ( k , i ) = 1 ] ⌊ A i ⌋ ⌊ B j ⌋ ⌊ C k ⌋ \sum\limits_{i=1}^A\sum\limits_{j=1}^B\sum\limits_{k=1}^C[(i,j)=1][(j,k)=1][(k,i)=1]\left\lfloor\frac{A}{i}\right\rfloor\left\lfloor\frac{B}{j}\right\rfloor\left\lfloor\frac{C}{k}\right\rfloor i=1Aj=1Bk=1C[(i,j)=1][(j,k)=1][(k,i)=1]iAjBkC
∑ i = 1 A ∑ j = 1 B ∑ k = 1 C ⌊ A i ⌋ ⌊ B j ⌋ ⌊ C k ⌋ ∑ u ∣ ( i , j ) ∑ v ∣ ( j , k ) ∑ w ∣ ( k , i ) μ ( u ) μ ( v ) μ ( w ) \sum\limits_{i=1}^A\sum\limits_{j=1}^B\sum\limits_{k=1}^C\left\lfloor\frac{A}{i}\right\rfloor\left\lfloor\frac{B}{j}\right\rfloor\left\lfloor\frac{C}{k}\right\rfloor\sum\limits_{u|(i,j)}\sum\limits_{v|(j,k)}\sum\limits_{w|(k,i)}\mu(u)\mu(v)\mu(w) i=1Aj=1Bk=1CiAjBkCu(i,j)v(j,k)w(k,i)μ(u)μ(v)μ(w)
∑ u = 1 min ⁡ ( A , B ) ∑ v = 1 min ⁡ ( B , C ) ∑ w = 1 min ⁡ ( C , A ) μ ( u ) μ ( v ) μ ( w ) ∑ u ∣ i & v ∣ i ∑ v ∣ j & w ∣ j ∑ w ∣ k & u ∣ k ⌊ A i ⌋ ⌊ B j ⌋ ⌊ C k ⌋ \sum\limits_{u=1}^{\min(A,B)}\sum\limits_{v=1}^{\min(B,C)}\sum\limits_{w=1}^{\min(C,A)}\mu(u)\mu(v)\mu(w)\sum\limits_{u|i\&v|i}\sum\limits_{v|j\&w|j}\sum\limits_{w|k\&u|k}\left\lfloor\frac{A}{i}\right\rfloor\left\lfloor\frac{B}{j}\right\rfloor\left\lfloor\frac{C}{k}\right\rfloor u=1min(A,B)v=1min(B,C)w=1min(C,A)μ(u)μ(v)μ(w)ui&vivj&wjwk&ukiAjBkC
∑ u = 1 min ⁡ ( A , B ) ∑ v = 1 min ⁡ ( B , C ) ∑ w = 1 min ⁡ ( C , A ) μ ( u ) μ ( v ) μ ( w ) ∑ [ u , v ] ∣ i ⌊ A i ⌋ ∑ [ v , w ] ∣ j ⌊ B j ⌋ ∑ [ w , u ] ∣ k ⌊ C k ⌋ \sum\limits_{u=1}^{\min(A,B)}\sum\limits_{v=1}^{\min(B,C)}\sum\limits_{w=1}^{\min(C,A)}\mu(u)\mu(v)\mu(w)\sum\limits_{[u,v]|i}\left\lfloor\frac{A}{i}\right\rfloor\sum\limits_{[v,w]|j}\left\lfloor\frac{B}{j}\right\rfloor\sum\limits_{[w,u]|k}\left\lfloor\frac{C}{k}\right\rfloor u=1min(A,B)v=1min(B,C)w=1min(C,A)μ(u)μ(v)μ(w)[u,v]iiA[v,w]jjB[w,u]kkC
后面三个当然可以预处理辣 设为 f ( x , y ) = ∑ y ∣ i ⌊ x i ⌋ f(x,y)=\sum\limits_{y|i}\left\lfloor\frac{x}{i}\right\rfloor f(x,y)=yiix 只需要处理 x = A ,    x = B ,    x = C x=A,\;x=B,\;x=C x=A,x=B,x=C 的情况。
∑ u = 1 min ⁡ ( A , B ) ∑ v = 1 min ⁡ ( B , C ) ∑ w = 1 min ⁡ ( C , A ) μ ( u ) μ ( v ) μ ( w ) f ( A , [ u , v ] ) f ( B , [ v , w ] ) f ( C , [ w , u ] ) \sum\limits_{u=1}^{\min(A,B)}\sum\limits_{v=1}^{\min(B,C)}\sum\limits_{w=1}^{\min(C,A)}\mu(u)\mu(v)\mu(w)f(A,[u,v])f(B,[v,w])f(C,[w,u]) u=1min(A,B)v=1min(B,C)w=1min(C,A)μ(u)μ(v)μ(w)f(A,[u,v])f(B,[v,w])f(C,[w,u])
熟悉的样子
对于 ( u , v , w ) (u,v,w) (u,v,w) 三元环,边是 f ( ) f() f() 点是 μ \mu μ
μ = 0 \mu=0 μ=0 的点不应存在。
而且:两点有边当且仅当 f ( , [ ] ) ≠ 0 f(,[])\ne0 f(,[])̸=0 也就是说,比如 ( u , v ) (u,v) (u,v) 应该有 [ u , v ] ≤ min ⁡ ( A , B , C ) [u,v]\le\min(A,B,C) [u,v]min(A,B,C) 才能连边
对于这样的两点我们连一条边,边权为 l c m lcm lcm 方便到时候算 f f f

建边怎么做呢?首先你要知道 max ⁡ ( A , B , C ) \max(A,B,C) max(A,B,C) 以内所有数的质因子 这个要埃筛
直接枚举两个数连边肯定会炸,所以先枚举 u u u 再枚举子集 ( u , v ) (u,v) (u,v) 最后直接得到 v v v
或者枚举 g c d gcd gcd 然后搞出 u u u v v v
(实际上暴枚判断mu gcd然后continue也可以,而且不用埃筛(线性筛即可)。不过常数可能有、、、大)
(大就大吧,好写啊。。)
复杂度 O ( 卡 过 ) O(卡过) O()
O ( 卡 过 ) < < O ( ∑ n = 1 max ⁡ ( A , B , C ) 3 ω ( n ) ) O(卡过)<<O\left(\sum\limits_{n=1}^{\max(A,B,C)}3^{\omega(n)}\right) O()<<O(n=1max(A,B,C)3ω(n))

然后对于每次询问就三元环计数。边定向+暴枚 O ( m m ) O(m\sqrt{m}) O(mm )
emm 关于 m m m 的大小嘛 有一个非常松的上界 ( 729 × 1 0 5 ) (729\times10^5) (729×105) 实际上实践一下就发现挺少的
7 × 1 0 5 7\times10^5 7×105 级别。然后大概大概可以过。


好啊 有没有发现 很卡常数嘛 你还要处理各种细节 比如两个/三个点重复的情况需要额外算。。

谁能告诉我为啥我的 vectorO2 反而变慢了,,,

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define R register
const int MOD = 1e9 + 7;
const int MAXN = 1e5 + 5;
const int MAXA = 1e5;
int T, A, B, C, Mx, Mn, PrimeList[MAXN], Mu[MAXN], Deg[MAXN], Mark[MAXN], Stray[MAXN];
long long Fa[MAXN], Fb[MAXN], Fc[MAXN], Ans;
bool NotPrime[MAXN];
struct Minimal
{
     
	int v, w;
	Minimal(const int& vv = 0, const int& ww = 0) {
      v = vv, w = ww;}
};
vector<Minimal>e[MAXN];
int tot;
struct St
{
     
	int u, v, w;
	St(const int& uu = 0, const int& vv = 0, const int& ww = 0) {
      u = uu; v = vv; w = ww;}
}Edg[800005];
int gcd(const int& a, const int& b)
{
     
	return !b?a:gcd(b,a%b);
}
long long Calc(const int& a, const int& b, const int& c)
{
     
	return Fa[a] * Fb[b] * Fc[c] +
		   Fa[a] * Fb[c] * Fc[b] +
		   Fa[b] * Fb[a] * Fc[c] +
		   Fa[b] * Fb[c] * Fc[a] +
		   Fa[c] * Fb[a] * Fc[b] +
		   Fa[c] * Fb[b] * Fc[a] ;
}
int main()
{
     
	NotPrime[0] = NotPrime[1] = 1; Mu[1] = 1;
	for (R int t, i = 2; i <= MAXA; ++i)
	{
     
		if (!NotPrime[i]) PrimeList[++PrimeList[0]] = i, Mu[i] = -1;
		for (R int j = 1; j <= PrimeList[0] && (t = i * PrimeList[j]) <= MAXA; ++j)
		{
     
			NotPrime[t] = 1;
			if (!(i % PrimeList[j])) break;
			Mu[t] = -Mu[i];
		}
	}
	scanf("%d", &T);
	R long long f;
	while (T--)
	{
     
		scanf("%d%d%d", &A, &B, &C); Mx = max(max(A, B), C); Mn = min(min(A, B), C); tot = Ans = 0;
		fill(Fa, Fa + Mx + 1, 0); fill(Fb, Fb + Mx + 1, 0); fill(Fc, Fc + Mx + 1, 0);
		fill(Deg, Deg + Mx + 1, 0); fill(Mark, Mark + Mx + 1, 0);
		for (R int i = 1; i <= Mx; ++i) e[i].clear();
		for (R int i = 1; i <= A; ++i) for (R int j = i; j <= A; j += i) Fa[i] += A / j;
		for (R int i = 1; i <= B; ++i) for (R int j = i; j <= B; j += i) Fb[i] += B / j;
		for (R int i = 1; i <= C; ++i) for (R int j = i; j <= C; j += i) Fc[i] += C / j;
		for (R int i = 1; i <= Mn; ++i) Ans += Mu[i] * Fa[i] * Fb[i] * Fc[i];
		for (R int x, i = 1; i <= Mx; ++i)
		{
     
			if (!Mu[i]) continue;
			for (R int j = 1, t = i; t <= Mx; ++j, t += i)
			{
     
				if (!Mu[t]) continue;
				f = 1ll * t * (j + 1);
				for (R int k = j + 1; f <= 1ll * Mx; ++k, f += t)
				{
     
					if (!Mu[x = i * k]) continue;
					if (j == 1 || k == 1 || gcd(j, k) == 1)
					{
     
						Ans += Mu[x] * (Fa[t] * Fb[f] * Fc[f] + Fa[f] * Fb[t] * Fc[f] + Fa[f] * Fb[f] * Fc[t]);
						Ans += Mu[t] * (Fa[x] * Fb[f] * Fc[f] + Fa[f] * Fb[x] * Fc[f] + Fa[f] * Fb[f] * Fc[x]);
						++Deg[x], ++Deg[t]; Edg[++tot] = St(t, x, f);
					}
				}
			}
		}
		for (R int i = 1; i <= tot; ++i)
		{
     
			R int &u = Edg[i].u, &v = Edg[i].v;
			if (Deg[u] > Deg[v] || (Deg[u] == Deg[v] && u < v)) e[u].push_back(Minimal(v, Edg[i].w));
			else e[v].push_back(Minimal(u, Edg[i].w));
		}
		for (R int tt, i = 1; i <= Mx; ++i)
		{
     
			tt = e[i].size();
			for (R int j = 0; j < tt; ++j) Mark[e[i][j].v] = i, Stray[e[i][j].v] = e[i][j].w;
			for (R int kksk, u, v, j = 0; j < tt; ++j)
			{
     
				u = e[i][j].v; kksk = e[u].size();
				for (R int k = 0; k < kksk; ++k)
				{
     
					v = e[u][k].v;
					if (Mark[v] == i) Ans += Calc(Stray[v], e[i][j].w, e[u][k].w) * Mu[i] * Mu[u] * Mu[v];
				}
			}
		}
		printf("%lld\n", Ans % MOD);
	}
	return 0;
}

你可能感兴趣的:(vector,三元环计数,计数,莫比乌斯反演,常数优化)