POJ3691--Sky Code(容斥)

26 篇文章 0 订阅

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值