CSU1801(第十二届湖南省大学生计算机程序设计竞赛(热身赛)- D)

来源:互联网 发布:iphone 充电电流 软件 编辑:程序博客网 时间:2024/06/04 17:57

Problem : Mr. S’s Romance
Description :

给你n个数,把每个数都分解成素因子放进一个盒子中,要你从中至少抽一个数字相乘起来使得乘积是完全平方数。问有多少种方式。

Solution :

组合数公式+乘方快速幂+小优化。首先分解每个数。这里分解的时候要优化下,如果分解剩下来的数直接是一个素数,那么就把这个素因子的个数+1,然后直接跳出循环。然后就是组合,我们把盒子中的数按照素数分类,得到每个素数的个数,要想相乘起来的数字是完全平方数。那么每个素数取的个数就是偶数个。这样对于每个素数能取的方式总数就是f(ai)=(0ai)+(2ai)+(4ai)+。而这个求和是有公式的:f(ai)=2ai1。那么答案就是ans=f(a0)f(a1)f(a2)。但是题目中说了不能一个都不取,那么最终答案就是ans=ans1

Code(C++) :

#include <stdio.h>#include <string.h>#include <iostream>#define MAXN 1000005using namespace std;typedef long long LL;bool isprime[MAXN];int prime[MAXN];int indexnum[MAXN];int num;const int TOP=80000;const LL MOD=1000000000LL+7;int get_prime(){    memset(isprime,true,sizeof(isprime));    isprime[1]=false;    for(int i=2;i*i<MAXN-4;i++)        if(isprime[i])            for(int j=2;i*j<MAXN-4;j++)                isprime[i*j]=false;    num=0;    for(int i=1;i<MAXN-4;i++)        if(isprime[i])            indexnum[i]=num,prime[num++]=i;    return num;}int a[TOP];void deal(int x){    for(int i=0;i<num;i++){        if(isprime[x]){            a[indexnum[x]]++;            break;        }        while(x%prime[i]==0){            a[i]++;            x/=prime[i];        }        if(x==1)            break;    }}LL mul(LL x,LL n,LL mod){    LL tmp=x;    LL ans=1;    while(n){        if(n&1){            ans*=tmp;            ans%=mod;        }        tmp*=tmp;        tmp%=mod;        n>>=1;    }    return ans%mod;}int main(){    //freopen("in.data","r",stdin);    get_prime();    int T,K=1;    for(cin>>T;T--;){        int n;        scanf("%d",&n);        memset(a,0,sizeof(a));        for(int i=0;i<n;i++){            int tmp;            scanf("%d",&tmp);            deal(tmp);        }        LL ans=1;        for(int i=0;i<num;i++)            if(a[i])                ans=ans*mul(2,a[i]-1,MOD)%MOD;        ans=(ans-1+MOD)%MOD;        printf("Case #%d:\n%lld\n",K++,ans);    }    return 0;}
0 0
原创粉丝点击