题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=71738
题意:给你一个整数序列a1, a2, a3, ... , an。求gcd(ai, aj) = 1 且 i < j的对数。
思路:利用莫比乌斯反演很快就能得到公式,但是求解时我们要知道序列中1, 2, 3, ... , max(a1, a2, ... , an)的倍数各是多少。我们用num[i]=k,来表示序列中有k个数是i的倍数,那么这部分对结果的影响是mu[i]*(k - 1) * k / 2。最后的结果就是sigma(mu[i]*(k - 1) * k / 2)。
code:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 typedef long long LL; 6 const int MAXN = 250000; 7 int num[MAXN]; // num[i]表示 满足(i|ak)的个数 8 int tmp[MAXN]; // 标记哪些数有 9 bool check[MAXN]; 10 int primes[MAXN]; 11 int mu[MAXN]; 12 13 void moblus() 14 { 15 memset(check, false, sizeof(check)); 16 mu[1] = 1; 17 int cnt = 0; 18 for (int i = 2; i < MAXN; ++i) { 19 if (!check[i]) { 20 primes[cnt++] = i; 21 mu[i] = -1; 22 } 23 for (int j = 0; j < cnt; ++j) { 24 if (i * primes[j] > MAXN) break; 25 check[i * primes[j]] = true; 26 if (i % primes[j] == 0) { 27 mu[i * primes[j]] = 0; 28 break; 29 } else { 30 mu[i * primes[j]] = -mu[i]; 31 } 32 } 33 } 34 } 35 36 int main() 37 { 38 moblus(); 39 int n; 40 while (scanf("%d", &n) != EOF) { 41 memset(num, 0, sizeof(num)); 42 memset(tmp, 0, sizeof(tmp)); 43 int tmax = 0; 44 for (int i = 0; i < n; ++i) { 45 int x; 46 scanf("%d", &x); 47 ++tmp[x]; 48 tmax = max(tmax, x); 49 } 50 for (int i = 1; i <= tmax; ++i) { 51 for (int j = i; j <= tmax; j += i) { 52 num[i] += tmp[j]; 53 } 54 } 55 LL ans = 0; 56 for (int i = 1; i <= tmax; ++i) { 57 ans += (LL)mu[i] * num[i] * (num[i] - 1) / 2; 58 } 59 printf("%lld\n", ans); 60 } 61 return 0; 62 }