LA 7048 Coprime 莫比乌斯反演

题意:

给出\(n(n \leq 10^5)\)个数字\(a_i(a_i \leq 10^5)\),从中选出\(3\)个数,使得这\(3\)个数两两互质或者两两不互质

分析:

可以说这是《训练指南》\(P_{105}\)问题\(6\)的原题。
\(n\)个数看成\(n\)个顶点,如果两数互质连一条白边,不互质连一条黑边。
那么我们要计数的就是单色三角形的个数。
\(n\)个数中选\(3\)个数,一共有\(C_n^3\)种方案,正面不容易计算所以我们反面计算单色三角形的个数。
在一个非单色三角形中,恰好有两个顶点连接两条异色边。
而且有公共顶点的两条异色边对应一个非单色三角形。
假设与\(a_i\)互质的数字的个数为\(b_i\)(相当于连了\(b_i\)条白边),那么与\(a_i\)不互质的数字的个数为\(n-1-b_i\)(连了\(n-1-b_i\)条黑边)
每个非单色三角形被计算了两次,所以对应的个数为$ \frac {1} {2} \sum{b_i (n-1-b_i)}\( 最后单色三角形的个数就是\)C_n^3$减去非单色三角形的个数。

关于计算与\(a_i\)互质的数字的个数,根据莫比乌斯反演公式有 $ \sum{\mu(d) cnt_d, (d | a_i)} \(,其中\)cnt_d\(为\)d$的倍数的个数。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

typedef long long LL;
const int maxn = 100000;

int mu[maxn + 10], pcnt, prime[maxn];
bool vis[maxn + 10];
vector<int> factors[maxn + 10];

void preprocess() {
	pcnt = 0;
	mu[1] = 1;
	for(int i = 2; i <= maxn; i++) {
		if(!vis[i]) {
			mu[i] = -1;
			prime[pcnt++] = i;
		}
		for(int j = 0; j < pcnt && i * prime[j] <= maxn; j++) {
			vis[i * prime[j]] = true;
			if(i % prime[j] != 0) mu[i * prime[j]] = -mu[i];
			else {
				mu[i * prime[j]] = 0;
				break;
			}
		}
	}

	for(int i = 2; i <= maxn; i++) if(mu[i])
		for(int j = i; j <= maxn; j += i) factors[j].push_back(i);
}

int n, a[maxn + 10], cnt[maxn + 10];

int main()
{
	preprocess();
	
	int T; scanf("%d", &T);
	while(T--) {
		scanf("%d", &n);
		
		memset(cnt, 0, sizeof(cnt));
		for(int i = 0; i < n; i++) {
			scanf("%d", a + i);
			for(int d : factors[a[i]]) cnt[d]++;
		}

		LL ans = 0;
		for(int i = 0; i < n; i++) {
			LL coprime = n;
			for(int d : factors[a[i]]) coprime += mu[d] * cnt[d];
			if(a[i] == 1) coprime--;
			ans += coprime * (n - 1 - coprime);
		}
		ans >>= 1;
		LL tot = (LL)n * (n-1) * (n-2) / 6;
		printf("%lld\n", tot - ans);
	}

	return 0;
}
posted @ 2015-10-25 00:17  AOQNRMGYXLMV  阅读(243)  评论(0编辑  收藏  举报