POJ3904 Sky Code (容斥原理)

来源:互联网 发布:java中package的作用 编辑:程序博客网 时间:2024/05/21 10:20

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
42 3 4 5 42 4 6 8 72 3 4 5 7 6 8
Sample Output
1 0 34

这道题的题意是输入一个数N,再输入N个1到10000的数,从这N个数中选出4个数,使得这四个数的公因数为1。求有多少组这样的四个数。

举个例子来说明吧,这个题目只要明白了做法, 就很好做了。不明白做法,硬看很难看懂。

假如输入的是  4       30 30 30 30   因为公因数不只有1,所以答案是0。

这道题可以用逆向的思维来求,先求出公因数不只有1的情况,再用所有的情况减去不只有1的情况。所有的情况可以用组合数在求,即 for(i=4;i<maxn;i++)  node[i]=i*(i-1)*(i-2)*(i-3)/24;    node[i]指的是i个数(i>=4)选取4个有node[i]种方式来选取。将四个数分解质因数,求得质因数为2、3、5,并保存在prime数组中,prime[0]=2,prime[1]=3,prime[2]=5。用num[i]数组统计i因子在N个数的所有质因子中的个数,此样例为num[2 3 5 6 10 15 30]=4,其余均为0。用vist[i]数组来统计i因子是奇数还是偶数。最后奇加偶减,用ans来表示公因数不只有1的个数,最后用之前求得组合数组node[N]减去ans,求出最后结果。因为数据可能比较大,所以用的long long型。

这是测试的数据。


最后附上代码,代码不是我敲得,是我改的别人的,测试所用的语句我注释掉了,想要测试的可以取消注释。

/*42 3 4 542 4 6 872 3 4 5 7 6 8430 30 30 30430 30 30 21*/#include<stdio.h>#include<string.h>using namespace std;#define LL long long#define maxn 10005LL node[maxn],num[maxn],vist[maxn],prime[maxn];void Init(){    LL i;    for(i=4;i<maxn;i++)//求组合数,即i个数里面选择4个数的选择的种类有几种。        node[i]=i*(i-1)*(i-2)*(i-3)/24;}void make_count(int m){    int i,j,tmp,flag,cnt=0;    for(i=2;i*i<=m;i++)//求m的质因数,保存在prime数组里面        if(m&&m%i==0)        {            prime[cnt++]=i;            while(m&&m%i==0)                m/=i;        }    if(m>1)        prime[cnt++]=m;    //printf("cnt:%d\n",cnt);    for(i=1;i<(1<<cnt);i++)//i取1到2^3-1    {        tmp=1,flag=0;        for(j=0;j<cnt;j++) //j取0到2            if(i&(1<<j)) //意思是如果i=2^j,则为真。可以写成if(i==2^j)                flag++,tmp*=prime[j];        num[tmp]++;  //统计当前因子出现的次数        vist[tmp]=flag; //记录当前因子是奇数个还是偶数个,2 3 5=1   6 10 15=2  30=3  大于1的为多了的    }    /*    printf("num[i](1<=i<=30):");    for(i=1;i<=30;i++)        printf("%d ",num[i]);    printf("\n");    printf("vist[i](1<=i<=30):");    for(i=1;i<=30;i++)        printf("%d ",vist[i]);    printf("\n");    */}int main(){    Init();    int n,i,x;    while(~scanf("%d",&n))    {        memset(num,0,sizeof(num));        memset(vist,0,sizeof(vist));        for(i=0;i<n;i++)        {            scanf("%d",&x);            make_count(x);        }        LL ans=0;        for(i=1;i<maxn;i++)            if(num[i]) //如果存在这样的因子,即因子出现次数大于0            {                if(vist[i]&1)  //当前因子为奇数,加                    ans+=node[num[i]];                else           //当前因子为偶数,减                    ans-=node[num[i]];            }        printf("%I64d\n",node[n]-ans);    }    return 0;}


原创粉丝点击