Problem : Mr. S’s Romance
Description :
给你 n 个数,把每个数都分解成素因子放进一个盒子中,要你从中至少抽一个数字相乘起来使得乘积是完全平方数。问有多少种方式。
Solution :
组合数公式+乘方快速幂+小优化。首先分解每个数。这里分解的时候要优化下,如果分解剩下来的数直接是一个素数,那么就把这个素因子的个数+1,然后直接跳出循环。然后就是组合,我们把盒子中的数按照素数分类,得到每个素数的个数,要想相乘起来的数字是完全平方数。那么每个素数取的个数就是偶数个。这样对于每个素数能取的方式总数就是
f(ai)=(0ai)+(2ai)+(4ai)+…… 。而这个求和是有公式的: f(ai)=2ai−1 。那么答案就是 ans=f(a0)∗f(a1)∗f(a2)∗…… 。但是题目中说了不能一个都不取,那么最终答案就是 ans=ans−1 。
Code(C++) :
#include <stdio.h>
#include <string.h>
#include <iostream>
#define MAXN 1000005
using 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;
}