HDU 5702 Coprime (莫比乌斯反演+反向思维)*

Coprime

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


 

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

 

 

Recommend

liuyiding   |   We have carefully selected several similar problems for you:  6447 6446 6445 6444 6443 

 

#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
using namespace std;

#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)

#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define ll long long

const int  maxn =1e5+5;
const int mod=1e9+7;

int num[maxn],cnt[maxn],vis[maxn];///一个是统计数组,一个是最终计算答案的数组,一个是标记数组
int t,n,x,ub;
int a[maxn];
/*
题目大意:给定n个数,
然后求三元组,三元组满足要求:互质,互不质(汗。。。)

从反面考虑的,比较简单,正面情况比较多。
考虑对于一个数,集合可以划分为与其互质和与其不互质,
那么对于这个数答案的贡献就是(n-s-1)*s,
但通过简单的模拟也可以察觉,这样的方式有重复,重复度是2,最后统计时消去即可。
其实这样也不严谨,可以这样说重复度虽然不严格是2,但是除以2确实可以消去,
因为重复度不超过3,三元组要想满足总共就三种摆放方式,。
比如2,5,10.

下面就是经典问题了,给定一个数字集合,求与x互质的个数。
ans=f(x)=sigma (d|x) miu(d)*num(d),其中num(d)是集合中d 的倍数的个数。

*/


///筛法求莫比乌斯函数
int miu[maxn],prim[maxn],tot=0;
void sieve()
{
    int mark[maxn];  memset(mark,0,sizeof(mark));
    miu[1]=1;
    for(int i=2;i<maxn;i++)
    {
        if(!mark[i])
        {
            prim[tot++]=i;
            miu[i]=-1;
        }
        for(int j=0;j<tot;j++)
        {
            ll k=prim[j]*i;
            if(k>=maxn) break;
            mark[k]=1;
            if(i%prim[j])   miu[k]=-miu[i];
            else   break;
        }
    }
}

int main()
{
    sieve();
    scanf("%d",&t);
    while(t--)
    {
        memset(vis,0,sizeof(vis));
        memset(cnt,0,sizeof(cnt));
        memset(num,0,sizeof(num));

        scanf("%d",&n);
        ub=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x);
            a[i]=x;
            vis[x]=1;
            ub=max(ub,x);
        }

        for(int i=1;i<=ub;i++)
        {
            if(miu[i])
            {
                for(int j=i;j<=ub;j+=i)  if(vis[j]) num[i]++;///在给定的集合中,i的倍数有多少
                num[i]=miu[i]*num[i];
                for(int j=i;j<=ub;j+=i) cnt[j]+=num[i];
            }
        }

        cnt[1]--;

        ll ans=(ll)n*(n-1)*(n-2)/6,s=0;
        for(int i=0;i<n;i++) s+=(ll)cnt[a[i]]*(n-1-cnt[a[i]]);///这里不能边减边除。。。会因为整除有精度误差而对答案造成影响
        printf("%lld\n",ans-s/2);
    }
    return 0;
}

 


版权声明:本文为qq_37451344原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。