题目大意:给出一个用m个ai乘起来表示的n,求出一个最大的k,使得存在一个d,使得d^k|n,并求出在这种情况下符合条件的d的个数
我们想求得答案,很自然的想要进行质因数分解,想要把n进行质因数分解,显然要把ai进行质因数分解
但是由于ai有点大,直接根号ai全部分解显然是不现实的
那么我们不妨考虑先筛出10^6以内的所有素数,然后用这些素数来筛ai
这样筛完之后,对于所有的ai,只可能有四种情况:
1.被筛干净变成了1,这样我们就算处理完了这个数
2.被筛成了一个大于10^6的大质数p,我们可以用Miller-Rabin来检验剩下的数是否属于这种情况
3.被筛成了一个大于10^6的大质数p的平方,我们可以直接开根来判断是否属于这种情况
4.被筛成了两个大于10^6的大质数p,q的乘积
由于10^6以内的素数我们全都筛过了,所以一定不会出现剩下的数包含三个可重质因子的情况
前三种情况我们可以非常(轻松)地解决,现在考虑最后一种情况
若存在一个大质数p在n中出现2次以上,则其必然至少在两个这种形态的数中出现(上面的情况暂时不考虑)
所以我们可以去重之后对剩下的ai两两做gcd,把gcd不为1的拿出来,这是可能出现多次的素数,剩下的大质数我们不需要知道他们具体是几,只需要知道有多少个这样的数,他们的出现次数均为1就好了
统计出n中每个质数出现了多少次后,我们可以轻松算出k,设质数出现次数=k的有x个,则第二问答案为2^x-1
这里可能会爆longlong,所以要用高精度
具体实现上可能会有一些细节问题,参见代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
#define max(x,y) ((x)>(y)?(x):(y))
#define N 1000010
using namespace std;
long long p[N],cnt;
bool he[N];
void getp()
{
long long i,j;
for(i=2;i<=1000000;i++)
{
if(!he[i]) cnt++,p[cnt]=i;
for(j=1;j<=cnt&&i*p[j]<=1000000;j++)
{
he[i*p[j]]=true;
if(i%p[j]==0) break;
}
}
}
long long a[610],v[610];
map<long long,long long>P;
map<long long,bool>Q[610];
long long gcd(long long x,long long y)
{
if(x==0) return y;
return gcd(y%x,x);
}
bool psqr(long long x)
{
long long t=(int)sqrt(x);
return t*t==x;
}
long long ran(long long n)
{
return (((long long)rand()<<30)+rand())%n+1;
}
long long mul(long long a,long long b,long long p)
{
long long tmp=a*b-(long long)((long double)a/p*b+1e-7)*p;
return (tmp+p)%p;
}
long long ksm(long long d,long long c,long long mod)
{
if(c==0) return 1;
if(c==1) return d;
if(c%2==0) return ksm(mul(d,d,mod),c/2,mod);
else return mul(ksm(mul(d,d,mod),c/2,mod),d,mod);
}
bool MillerRabin(long long n,int T)
{
long long r=n-1,s=0;
if(n%2==0) return false;
while(r%2==0)
r/=2,s++;
while(T--)
{
long long A=ran(n-3)+1,ss=s;
A=ksm(A,r,n);
long long la=A;
while(ss--)
{
A=mul(A,A,n);
if(A==1&&la!=n-1&&la!=1) return false;
la=A;
}
if(A!=1) return false;
}
return true;
}
struct ppp
{
int clong,a[610];
ppp()
{
clong=1;
memset(a,0,sizeof(a));
}
void jinwei()
{
int i;
for(i=1;i<clong;i++)
{
a[i+1]+=a[i]/10;
a[i]%=10;
}
while(a[clong]>=10)
{
clong++;
a[clong]=a[clong-1]/10;
a[clong-1]%=10;
}
}
void print()
{
int i;
for(i=clong;i>=1;i--)
printf("%d",a[i]);
}
};
ppp ret;
ppp operator *(ppp &x,int y)
{
int i;
ret.clong=x.clong;
for(i=1;i<=x.clong;i++)
ret.a[i]=2*x.a[i];
ret.jinwei();
return ret;
}
ppp ANS;
int main()
{
getp();
long long n;
scanf("%lld",&n);
long long i,j;
long long x,y;
for(i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
j=1;
while(a[i]!=1&&j<=cnt)
{
while(a[i]%p[j]==0)
{
a[i]/=p[j];
P[p[j]]++;
}
j++;
}
}
sort(a+1,a+n+1);
for(i=1;i<n;i++)
{
if(a[i+1]==a[i])
{
v[i]++;
for(j=i+1;j<n;j++)
a[j]=a[j+1];
n--;i--;
}
}
for(i=1;i<=n;i++)
v[i]++;
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
{
x=gcd(a[i],a[j]);
if(x!=1) Q[i][x]=Q[j][x]=true;
}
long long maxn=1,ans=0;
map<long long,bool>::iterator it;
for(i=1;i<=n;i++)
if(a[i]!=1)
{
if(psqr(a[i]))
P[(long long)sqrt(a[i])]+=v[i]*2;
else
{
if(Q[i].size()==2)
{
it=Q[i].begin();
P[it->first]+=v[i];
it++;
P[it->first]+=v[i];
}
else if(Q[i].size()==1)
{
it=Q[i].begin();
P[it->first]+=v[i];
if(it->first!=a[i])
{
if(v[i]>maxn) maxn=v[i],ans=1;
else if(v[i]==maxn) ans++;
}
}
else if(MillerRabin(a[i],10))
{
if(v[i]>maxn) maxn=v[i],ans=1;
else if(v[i]==maxn) ans++;
}
else
{
if(v[i]>maxn) maxn=v[i],ans=2;
else if(v[i]==maxn) ans+=2;
}
}
}
map<long long,long long>::iterator IT;
for(IT=P.begin();IT!=P.end();IT++)
{
if(IT->second==maxn) ans++;
else if(IT->second>maxn) maxn=IT->second,ans=1;
}
printf("%lld\n",maxn);
ANS.a[1]=1;
for(i=1;i<=ans;i++)
ANS=ANS*2;
ANS.a[1]--;
ANS.print();
}