POJ3691--Sky Code(容斥)

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章