POJ3691--Sky Code(容斥)

来源:互联网 发布:山西省卫生厅网络舆情 编辑:程序博客网 时间:2024/06/11 06:29

Do more with less

Discussion

Stancu likes space travels but he is a poor software developer and will never be able to buy his own spacecraft. That is why he is preparing to steal the spacecraft of Petru. There is only one problem – Petru has locked the spacecraft with a sophisticated cryptosystem based on the ID numbers of the stars from the Milky Way Galaxy. For breaking the system Stancu has to check each subset of four stars such that the only common divisor of their numbers is 1. Nasty, isn’t it? Fortunately, Stancu has succeeded to limit the number of the interesting stars to N but, any way, the possible subsets of four stars can be too many. Help him to find their number and to decide if there is a chance to break the system.

Input

In the input file several test cases are given. For each test case on the first line the number N of interesting stars is given (1 ≤ N ≤ 10000). The second line of the test case contains the list of ID numbers of the interesting stars, separated by spaces. Each ID is a positive integer which is no greater than 10000. The input data terminate with the end of file.

Output

For each test case the program should print one line with the number of subsets with the asked property.

Sample Input

4
2 3 4 5
4
2 4 6 8
7
2 3 4 5 7 6 8

Sample Output

1
0
34

题意

在给定个数中选4个数,是他们的最大公约数为1,求有几种选择方式。

思路

利用容斥原理,从M个数中选4个一共有Cm,4中,减去最大公约数不唯一的即可。
将一个数进行因式分解,会得到它的因子,如果将所以数都进行因式分解,如果其中的某4个数具有相同的因子,那么说明这四个数不能给选到一起,用Cm,4减掉这些情况就好,那么问题来了,比如,现在这些数,以2为因子的数有x个,以3为因子的有y个,那么要用Cm,4Cx,4Cy,4但是又有些数既以2为因子又以3为因子,这说明多减了,还要加上以2,3为因子的数,这就是容斥原理。

代码

#include <iostream>#include <cstring>using namespace std;const int maxn = 10005;int a[maxn];int prime[maxn];bool vis[maxn];long long cx4(int x){//求c(x,4)    return (long long )x*(x-1)*(x-2)*(x-3)/24;}void gao(int n){//搞一下    int top = 0;    for(int i = 2; i*i <= n; i++)    {        if(n % i == 0)            prime[top++] = i;        while(n % i == 0)            n /= i;    }    if(n > 1)        prime[top++] = n;    for(int i = 1; i < (1 << top); i ++)    {        int temp = 1;        bool flag = false;        for(int j = 0; j < top; j ++)            if( i & 1 << j)            {//这里是神奇代码,实现容斥。                temp *= prime[j];                flag = ! flag;            }        a[temp] ++;        vis[temp] = flag;    }}int main(){    int t;    while( cin >> t)    {        memset(a,0,sizeof(a));        memset(prime,0,sizeof(prime));        for(int i = 0; i < t; i ++)        {            int m;            cin >> m;            gao(m);        }        long long ans = cx4(t);        for(int i = 0; i <= maxn; i ++)        {            if(a[i])            {                if(vis[i])                    ans -= cx4(a[i]);                else                    ans += cx4(a[i]);            }        }        cout << ans << endl;    }    return 0;}