hdu5072 Coprime

来源:互联网 发布:c语言产生随机数 编辑:程序博客网 时间:2024/05/16 17:51

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.

可以把原问题分解为两个子问题,一是求数列中与某个数互质的数的个数,二是单色三角形问题。
对于子问题一,先扫一遍对每个数进行质因数分解,枚举因数统计每个数作为数列中的一个数的因数出现的次数,再扫一遍枚举因数用容斥原理计算。
对于子问题二,如果对于a[i]有x个数与他互质,可以构成x * (n-x+1)个不满足要求的三元组。对所有a[i]的上述值求和,每个三元组被统计两遍。

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;#define LL long longint cnt[100010],a[100010],tem[100010][10],num[100010],n;int main(){    int T,i,j,k,m,x,u,y;    LL ans;    scanf("%d",&T);    while (T--)    {        memset(cnt,0,sizeof(cnt));        scanf("%d",&n);        ans=0;        for (i=1;i<=n;i++)          scanf("%d",&a[i]);        for (i=1;i<=n;i++)        {            m=sqrt(a[i]+0.5);            num[i]=0;            for (j=2;j<=m;j++)              if (a[i]%j==0)              {                tem[i][num[i]++]=j;                while (a[i]%j==0) a[i]/=j;              }            if (a[i]>1) tem[i][num[i]++]=a[i];            for (j=1;j<(1<<num[i]);j++)            {                x=1;                for (k=0;k<num[i];k++)                  if (1<<k&j)                    x*=tem[i][k];                cnt[x]++;            }        }        for (i=1;i<=n;i++)        {            u=0;            for (j=1;j<(1<<num[i]);j++)            {                x=1;                y=0;                for (k=0;k<num[i];k++)                  if (1<<k&j)                    x*=tem[i][k],y++;                if (y&1) u+=cnt[x]-1;                else u-=cnt[x]-1;            }            ans+=(LL)u*(n-u-1);        }        printf("%lld\n",(LL)n*(n-1)*(n-2)/6-ans/2);    }}
0 0
原创粉丝点击