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