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即为所求