POJ 3904 Sky Code(容斥)

Description

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元組,GCD(a,b,c,d)=1,問方案數開始並沒有什麼思路

我們想不考慮條件的總的方案數爲:C(n,4),這其中我們要去掉GCD>1的

那麼我們就要考慮素數因子之間的組合來容斥

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
using namespace std;
#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define CLEAR( a , x ) memset ( a , x , sizeof a )
const int INF=0x3f3f3f3f;
typedef long long LL;
int n,A[10100];
int num[10100];
int kind[10100];
LL f[10010],ans;
int v[10];
void init()
{
    for(int i=4;i<=10000;i++)
        f[i]=1LL*i*(i-1)*(i-2)*(i-3)/24;
}
void solve(int x)
{
    int m=0;
    for(int i=2;i*i<=x;i++)
    {
        if(x%i==0)
        {
            while(x%i==0)
                x/=i;
            v[m++]=i;
        }
    }
    if(x>1)
        v[m++]=x;
    for(int i=1;i<(1<<m);i++)
    {
        int c=0,l=1;
        for(int j=0;j<m;j++)
        {
            if(i&(1<<j))
            {
                c++;
                l*=v[j];
            }
        }
        num[l]++;
        kind[l]=c;
        if(c&1)
        {
            ans-=f[num[l]-1];
            ans+=f[num[l]];
        }
        else
        {
            ans+=f[num[l]-1];
            ans-=f[num[l]];
        }
    }
}
int main()
{
    init();
    while(~scanf("%d",&n))
    {
        CLEAR(num,0);
        CLEAR(kind,0);
        ans=0;
        REPF(i,1,n)
        {
            scanf("%d",&A[i]);
            solve(A[i]);
        }
        printf("%lld\n",f[n]-ans);
    }
    return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章