POJ 3904 Sky Code

来源:互联网 发布:linux 启动telnet命令 编辑:程序博客网 时间:2024/05/19 13:44

题目地址: http://poj.org/problem?id=3904


题意:给出n个数,问找出4个数满足4个数最大公约数为1,最多有多少组。
思路:容斥原理,遍历每个数的素因子,奇数个加偶数个减,然后C(n,4)-sum。


//求得是n个数中,有多少组(a,b,c,d)的公约数为1,值得注意的是这四个数不一定两两互质。  
//所以我们从它的反面考虑,先求出公约数不为1的个数。  
//思路:把每个数素数分解,记录不重复素因子所能组成的因子,把这些因子的总数统计,并且统计每个因子是由多少个素因子组成  
//如这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即为所求


AC代码:

#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <string>#include <vector>#include <list>#include <deque>#include <queue>#include <iterator>#include <stack>#include <map>#include <set>#include <algorithm>#include <cctype>#include <cfloat>using namespace std;typedef __int64 LL;const int N=10005;const LL II=1000000007;const int INF=0x3f3f3f3f;const double PI=acos(-1.0);LL n,m,pri[N],num[N],co[N],p[N];void init(){    memset(p,0,sizeof(p));    memset(num,0,sizeof(num));    for(LL i=4;i<N;i++)//p[i]表示总共有多少种方法        p[i]=i*(i-1)*(i-2)*(i-3)/24;}LL prime(LL x){    LL i,j,numi=0;    for(i=2;i*i<=x;i++)        if(x%i==0)        {            pri[numi++]=i;            while(x%i==0)                x/=i;        }    if(x>1)        pri[numi++]=x;    return numi;}void dfs(LL k){    LL i,j,t,numi;    numi=prime(k);    LL sum=0;    for(i=1;i<(1<<numi);i++)    {        LL temp=1,k=0;        for(j=0;j<numi;j++)            if(i&(1<<j))            {   temp*=pri[j];   k++;    }        co[temp]++;//记录当前因子的个数        num[temp]=k;//记录当前因子是由多少个素因子组成    }}int main(){    LL i,j,T;    init();    while(~scanf("%I64d",&n))    {        memset(co,0,sizeof(co));        for(i=1;i<=n;i++)        {            scanf("%I64d",&m);            dfs(m);        }        LL sum=0;        for(i=0;i<N;i++)        {            if(!co[i])   continue;            if(num[i]&1)    sum+=p[co[i]];            else    sum-=p[co[i]];        }        printf("%I64d\n",p[n]-sum);    }    return 0;}


原创粉丝点击