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

博客围绕Coprime问题展开,给定n个人的唯一id号,要选3人组抵御邪恶,3人能交流的条件是id号两两互质或两两不互质。给出了时间、内存限制,输入输出要求及示例,需计算从n人中可选的3人组数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值