POJ 3904 Sky Code

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<stdio.h>
 4 #include<string.h>
 5 #define MAX 10005
 6 using namespace std;
 7 int cnt[MAX],num[MAX],prime[MAX];
 8 long long  p[MAX]; //必须用大整数 
 9 void Solve(int  n)
10 {
11     int i,j,tol=0;
12     for(i=2;i*i<=n;i++)//计算素因子个数 
13     {
14         if(n%i==0)
15         {
16             prime[tol++]=i;
17         }
18         while(n%i==0)
19             n/=i;
20     }
21     if(n!=1)        //如果本身就是大于n开方的素数,需要加一,这点不要忘记 
22     prime[tol++]=n;
23     for(i=1;i<(1<<tol);i++)//总共有1~2^tol-1个组合 
24     {
25         int  k=1;
26         int  sum=0;
27         for(j=0;j<tol;j++)//巧妙利用二进制来查找到所有素因子组合构成的数 
28         {
29             if(i&(1<<j))
30             {
31                 k*=prime[j];
32                 sum++;
33             }
34         }
35         cnt[k]++; //记录含有因子K的数的个数 
36         num[k]=sum;    //记录k中含有素因子的个数 
37     }
38 }
39 int main()
40 {
41    int m,n;
42    long long i; 
43    memset(p,0,sizeof(p));
44    memset(num,0,sizeof(num));
45    for(i=4;i<MAX;i++)        //先打表,提高效率,i<4时p[i]为0; 
46         p[i]=i*(i-1)*(i-2)*(i-3)/24;
47    while(~scanf("%d",&n))
48    {
49        memset(cnt,0,sizeof(cnt));
50        for(i=0;i<n;i++)
51        {
52            scanf("%d",&m);
53            Solve(m);        //求解其素因子,并统计相关数据 
54        }
55        long long ans=0;
56        for(int  i=0;i<MAX;i++)
57        {
58            if(cnt[i]>=4)//剪枝,必须大于等于四  
59            {
60                if(num[i]&1) //假如含有素因子个数为奇数,则加上;否则减去 
61                     ans+=p[cnt[i]];
62                else
63                        ans-=p[cnt[i]];
64            }
65        }
66        cout<<p[n]-ans<<endl; //最后用总的减去不符合的四元组个数 
67    }
68 }

思路:容斥原理,把每个数素数分解,记录不重复素因子所能组成的因子,把这些因子的总数统计,并且统计每个因子是由多少个素因子组成  
如这n个数中含2的个数为a,含3的个数为b,含6的个数为c,那么公约数大于1的总数为p=c(a,4)+c(b,4)-c(c,4),总的个数为c(n,4)  
用c(n,4)-p即为所求

原文地址:https://www.cnblogs.com/shihuajie/p/2980456.html