HDU 5072 Coprime(同色三角形+容斥)

来源:互联网 发布:最优化理论与方法 清华 编辑:程序博客网 时间:2024/04/28 04:39

题目大意:给你n个数,让你选出三个数,使得[(a, b) = (b, c) = (a, c) = 1] or [(a, b) ≠ 1 and (a, c) ≠ 1 and (b, c) ≠ 1]成立,问你有多少种选择方案。

思路:同色三角形+容斥。

首先说一下什么是同色三角形,《算法入门经典训练指南》P105,问题6中有提到,把每个数与之互质的数称为红边,不互质的称为黑边,这样求出来的非单色三角形就是不合法的个数的2倍,然后用C(n, 3)减去这个数就是结果。

所以现在最主要的就是求与多少个数与他不互质,我们先哈希处理出来所有的结果,然后统计每个数对应的个数,比如统计有2的数的个数,有3的数的个数,有4……然后枚举每一个数将其分解质因数,然后状压枚举所有的质因子看组成的数有多少种,我们需要容斥一下,奇加偶减,得到cnt,求出来所有不互质的个数,然后ans += cnt*(n-1-cnt);cnt(代表每个数有多少与之不互质)。

PS:第一次的代码有bug竟然也过了啊。。。

Coprime

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


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
151 3 9 10 2
 

Sample Output
4
 

Source
2014 Asia AnShan Regional Contest
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:  5161 5160 5157 5156 5153 
#include <algorithm>#include <iostream>#include <stdlib.h>#include <string.h>#include <iomanip>#include <stdio.h>#include <string>#include <queue>#include <cmath>#include <stack>#include <ctime>#include <map>#include <set>#define eps 1e-9///#define M 1000100///#define LL __int64#define LL long long///#define INF 0x7ffffff#define INF 0x3f3f3f3f#define PI 3.1415926535898#define zero(x) ((fabs(x)<eps)?0:x)#define mod 1000000007using namespace std;const int maxn = 100010;int f[maxn], k[maxn];int num[maxn];int vis[maxn];int t;int n;void Prime(){    t = 0;    memset(f, 0, sizeof(f));    for(int i = 2; i <= 100000; i++)    {        if(!f[i])            k[t++] = i;        for(int j = 0; j < t; j++)        {            if(i*k[j] > 100000)                break;            f[i*k[j]] = true;            if(i%k[j] == 0)                break;        }    }}void init(){    for(int i = 2; i <= maxn-10; i++)        for(int j = i+i; j <= maxn-10; j += i) vis[i] += vis[j];}vector<int> fx[maxn];void Del(){    for(int i = 0; i < n; i++)    {        fx[i].clear();        int x = num[i];        for(int j = 0; j < t; j++)        {            if(x == 1) break;            if(!f[x])            {                fx[i].push_back(x);                break;            }            if(x%k[j]) continue;            fx[i].push_back(k[j]);            while(x%k[j] == 0) x /= k[j];        }    }}int main(){    Prime();    int T;    cin >>T;    while(T--)    {        cin >>n;        memset(vis, 0, sizeof(vis));        for(int i = 0; i < n; i++)        {            scanf("%d",&num[i]);            vis[num[i]]++;        }        init();        Del();        LL ans = 0;        for(int i = 0; i < n; i++)        {            int sx = fx[i].size();            LL sum = 1;            LL xp = 0LL;            for(int j = 1; j < (1<<sx); j++)            {                int cnt = 0;                sum = 1;                for(int sk = 0; sk < sx; sk++)                {                    if(!((1<<sk)&j)) continue;                    cnt++;                    sum *= fx[i][sk];                }                if(cnt&1) xp += (vis[sum]-1);                else xp -= (vis[sum]-1);            }            ans += xp*(n-1-xp);        }        cout<<(n*(n-1LL)*(n-2LL)/6) - ans/2<<endl;    }}


0 0