HDU 5072 Coprime

传送门

Coprime

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 2074    Accepted Submission(s): 781


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
 

题目大意:

给了n(n<100000)个不同的数,要求的就是有多少个三元组,两两互素 或者 两两不互素。


解题思路:

可以参考一下 《算法竞赛入门经典 训练指南》(白书)  p105 问题6  同色三角形。

所以这个题 可以考虑反面,所以就用到容斥原理。这题可以换个角度想,可以将三个数看做三角形的三条边,互质即边的颜色为1,否则为0,那么要求的即为三条边颜色相同的三角形有多少个。对于每个数字求出与其不互质的个数k   那么  sum ( k*(n-1-k) )/2 就是相反的数目, 求每个数互质或者不互质的数有多少个,将每个数质因子分解,统计每个包含质因子x的数有多少个,然后在进行容斥原理,奇加偶减。

My Code:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long LL;

int scan()///输入外挂
{
    int res=0,ch,flag=0;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;

}

inline void out(LL a)///输出外挂
{
    if(a>9)
        out(a/10);
    putchar(a%10+'0');
}

const int MAXN = 2e5+5;

int p[MAXN];
bool prime[MAXN];
int k;
void isprime()
{
    memset(prime, false, sizeof(prime));
    k = 0;
    for(LL i=2; i<MAXN; i++)
    {
        if(!prime[i])
        {
            p[k++] = i;
            for(LL j=i*i; j<MAXN; j+=i)
                prime[j] = true;
        }
    }
}
int fac[MAXN/1000];
int cnt = 0;
void Dec(int m)
{
    cnt = 0;
    for(int i=0; p[i]*p[i]<=m&&i<k; i++)
    {
        if(m%p[i]==0)
        {
            fac[cnt] = p[i];
            while(m%p[i]==0)
                m /= p[i];
            cnt++;
        }
    }
    if(m > 1)
        fac[cnt++] = m;
}
int num[MAXN];
void Solve(int m)
{
    Dec(m);
    for(int i=1; i<(1<<cnt); i++)
    {
        int ans = 1;
        for(int j=0; j<cnt; j++)
            if(i & (1<<j))
                ans *= fac[j];
        num[ans]++;
    }
}
LL Get_ans(int m)
{
    Dec(m);
    LL ret = 0;
    for(int i=1; i<(1<<cnt); i++)
    {
        int sum = 0, ans = 1;
        for(int j=0; j<cnt; j++)
        {
            if(i & (1<<j))
            {
                sum++;
                ans *= fac[j];
            }
        }
        if(sum & 1)
            ret += num[ans];
        else
            ret -= num[ans];
    }
    ///cout<<ret<<endl;
    return ret;
}
LL Cal(int m)
{
    return (LL)m * (LL)(m-1) * (LL)(m-2) / 6;
}
int a[MAXN];
int main()
{
    ///cout<<Cal(66666);
    isprime();
    int T, m;
    T = scan();
    while(T--)
    {
        m = scan();
        memset(num, 0, sizeof(num));
        for(int i=0; i<m; i++)
        {
            a[i] = scan();
            Solve(a[i]);
        }
        LL ret = 0;
        for(int i=0; i<m; i++)
        {
            LL ans = Get_ans(a[i]);
            if(!ans)
                continue;
            ret += (ans-1)*(m-ans);
            ///cout<<ans<<endl;
        }
        ///cout<<ret<<endl;
        cout<<Cal(m)-ret/2<<endl;
    }
    return 0;
}


你可能感兴趣的:(HDU 5072 Coprime)