HDU 5072 Coprime (莫比乌斯反演+容斥+同色三角形)


Coprime

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)

Total Submission(s): 1469    Accepted Submission(s): 579

Problem Description

There are n people standing in a line. Each of them has a unique id number.
Now the Ragnarok is coming. We should choose 3 people to defend the evil. As a group, the 3 people should be able to communicate. They are able to communicate if and only if their id numbers are pairwise coprime or pairwise not coprime. In other words, if their id numbers are a, b, c, then they can communicate if and only if [(a, b) = (b, c) = (a, c) = 1] or [(a, b) ≠ 1 and (a, c) ≠ 1 and (b, c) ≠ 1], where (x, y) denotes the greatest common divisor of x and y.

We want to know how many 3-people-groups can be chosen from the n people.
 
Input
The first line contains an integer T (T ≤ 5), denoting the number of the test cases.
For each test case, the first line contains an integer n(3 ≤ n ≤ 105), denoting the number of people. The next line contains n distinct integers a1, a2, . . . , an(1 ≤ ai ≤ 105) separated by a single space, where ai stands for the id number of the i-th person.
 
Output
For each test case, output the answer in a line.
 
Sample Input
 
   
1 5 1 3 9 10 2
 
Sample Output
 
   
4
 
Source
2014 Asia AnShan Regional Contest

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5072

题目大意:给n个互不相同的数,从中选三个,求三个中两两都互质或者两两都不互质的组数

题目分析:开始想歪了,三个数两两都互质并不是说三个数的最大公约数为1,所以正着不好算,考虑算反面即三个中只有一对互质或者只有两对互质的情况,再用C(n,3)减即可,我们把三个数当做三角形的三个顶点A,B,C,枚举顶点A,不妨设A与B互质,A与C不互质,则这样就组成了一对反面情况,至于B,C可以互质也可以不互质,因此算出的结果要除2,具体的说,如果B,C互质,可以交换A,C,如果B,C不互质,可以交换A,B,这样都满足A与B互质,A与C不互质,因此设与A互质的数有k个,则A对答案的贡献为k * (n - k - 1) / 2,计算每个数字对反面情况的贡献数得到反面总的情况数,拿总数减即可,还要注意的是A的值不能为1,因为没有与1不互质的数,接下来就是如何计算k的值,枚举k的因子,它所有因子倍数的个数乘因子对应的莫比乌斯函数值就是k,这里其实直接包含了容斥的过程,它某个因子的倍数可能也是另外一个因子的倍数,举个例子,比如假设最大值为20,A为12,则:
因子 :                       1     2     3    4    6   12
莫比乌斯函数值:      1    -1    -1    0   1    0
因子倍数的个数:     20   10    6    5    3    1
因此答案为20 - 10 - 6 + 3 = 7,即在1到20中与12互质的数有7个,1,5,7,11,13,17,19

#include 
#include 
#include 
#define ll long long 
using namespace std;
int const MAX = 1e5 + 5;
int mob[MAX], p[MAX];
int a[MAX], num[MAX], has[MAX], cp[MAX];
bool prime[MAX];
int ma, n;

int Mobius()
{
    int pnum = 0;
    memset(prime, true, sizeof(prime));
    mob[1] = 1;
    for(int i = 2; i < MAX; i++)
    {
        if(prime[i])
        {
            p[pnum ++] = i;
            mob[i] = -1;
        }
        for(int j = 0; j < pnum && i * p[j] < MAX; j++)
        {
            prime[i * p[j]] = false;
            if(i % p[j] == 0)
            {
                mob[i * p[j]] = 0;
                break;
            }
            mob[i * p[j]] = -mob[i];
        }
    }
}

ll cal()
{
    ll all = (ll) n * (n - 1) * (n - 2) / 6;
    memset(cp, 0, sizeof(cp));
    memset(num, 0, sizeof(num));
    for(int i = 1; i <= ma; i++)
    {
        for(int j = i; j <= ma; j += i)
            num[i] += has[j];
        for(int j = i; j <= ma; j += i)
            cp[j] += mob[i] * num[i];
    }
    ll no = 0;
    for(int i = 0; i < n; i++)
        if(a[i] != 1)
            no += (ll) cp[a[i]] * (n - cp[a[i]] - 1);
    return all - no / 2;
}

int main()
{
    Mobius();
    int T;
    scanf("%d", &T);
    while(T--)
    {
        memset(has, 0, sizeof(has));
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
        {
            scanf("%d", &a[i]);
            has[a[i]] ++;
            ma = max(a[i], ma);
        }
        printf("%I64d\n", cal());
    }
}





 

你可能感兴趣的:(ACM,数论,组合数学)