数论小集合。
题目里第一问本质上要求的其实是 数a1*a2*a3*....*am(m<=600)分解质因数之后最大的指数k,第二问yy一下发现要求的就是 2^(指数是k的素数个数)-1
瓶颈在于我们如何求出这个质因数分解,ai<=10^18!
我们最多能找出ai在10^6(不到80000个素数)以内的质因子,我们就先找出小因子。
与下来只可能存在 p、p*q、p^2
p^2的情况可以很容易判定能够出来
我们又可以想到了大素数判定(笔者弱弱的不会写Miller-Rabin挖个坑以后来填吧)。
那么最后只剩下p*q的情况。
我们先把m个数两两做gcd,如果不为1那么就能把这数分解了。如果仍是没有分出来,那么我们也没有必要知道p、q是多少,因为我们只关心他的指数是1就可以了。
贴上代码——又丑又长又慢。。。。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define sqr(x) ( (int)(x)*(x) )
typedef long long LL;
const int Maxn=1000007;
LL x,xx,MD6,MD12,INF;
int n,tot,maxx,cnt,i,j,cb;
int prime[Maxn];
bool check[Maxn];
struct arr
{
LL dig; int sum;
bool operator <(const arr &x) const
{ return dig<x.dig; }
} A[Maxn],B[Maxn];
struct BIGINT
{
int a[500],h;
BIGINT operator +(const BIGINT &x)const
{
BIGINT ret; int p=0;
memset(ret.a,0,sizeof(ret.a));
for (int i=1;i<=h;i++){
ret.a[i]=a[i]+x.a[i]+p;
p=ret.a[i]/10;
ret.a[i]=ret.a[i]%10;
}
ret.h=h;
if (p>0) ret.a[++ret.h]=p;
return ret;
}
} ANS;
void init(){
for (i=2;i<Maxn;i++){
if (check[i]==0) prime[tot++]=i;
for (j=0;j<tot;j++){
if (i*prime[j]>=Maxn) break;
check[i*prime[j]]=1;
if (i%prime[j]==0) break;
}
}
}
LL mul(LL a,LL b,LL mod){
LL ret=0;
while (b){
if (b&1){
ret=ret+a;
if (ret>=mod) ret-=mod;
}
a<<=1; b>>=1;
if (a>=mod) a-=mod;
}
return ret;
}
LL qck(LL a,LL b,LL mod){
LL ret=1;
for (;b>0;b>>=1){
if (b&1) ret = mul(ret,a,mod);
a = mul(a,a,mod);
}
return ret;
}
bool prime_check(LL x){
for (int i=0;i<=5&&prime[i]<=x;i++)
if (qck((LL)prime[i],x-1,x)!=1) return 0;
return 1;
}
void work1(){
for (i=1;i<=n;i++){
scanf("%I64d",&x);
//printf("%I64d,",x);
for (j=0,xx=x;x>1&&j<tot;j++){
if (prime[j]>xx/prime[j]) break;
if (xx%prime[j]) continue;
A[cnt].dig=prime[j];
while (xx%prime[j]==0) A[cnt].sum++, xx/=prime[j];
cnt++;
}
if (xx>=Maxn){
if (prime_check(xx)){
A[cnt].dig=xx;
A[cnt++].sum=1;
} else
{
if ( sqr(sqrt(xx))==xx ){
A[cnt].dig=(int)sqrt(xx);
A[cnt++].sum=2;
} else
{
B[cb].dig=xx;
B[cb++].sum=1;
}
}
} else
if (xx>1) {
A[cnt].dig=xx;
A[cnt++].sum=1;
}
}
//printf("\n");
}
LL gcd(LL a,LL b){
while (b) b^=a^=b^=a%=b;
return a;
}
void work2(){
INF=1000000005; INF=INF*INF;
MD6=1000000; MD12=MD6*MD6;
sort(A,A+cnt);
for (i=cnt-2;i>=0;i--)
if (A[i].dig==A[i+1].dig){
A[i].sum+=A[i+1].sum;
A[i+1].dig=INF;
}
sort(A,A+cnt);
for (i=cnt-1;i>=0;i--)
if (A[i].dig>=INF) cnt--;
//printf("%d\n",cnt);
//for (i=0;i<cnt;i++)
// printf("%I64d^%d\n",A[i].dig,A[i].sum);
sort(B,B+cb);
for (i=cb-2;i>=0;i--)
if (B[i].dig==B[i+1].dig){
B[i].sum+=B[i+1].sum;
B[i+1].dig=INF;
}
sort(B,B+cb);
for (i=cb-1;i>=0;i--)
if (B[i].dig>=INF) cb--;
for (i=0;i<cb;i++){
for (j=cnt-1;A[j].dig>MD6;j--){
if (B[i].dig%A[j].dig==0)
B[i].dig/=A[j].dig, A[j].sum+=B[i].sum;
}
for (j=i+1;j<cb;j++)
if (gcd(B[i].dig,B[j].dig)>1){
A[cnt].dig=gcd(B[i].dig,B[j].dig);
A[cnt].sum=0;
if (B[i].dig%A[cnt].dig==0)
B[i].dig/=A[cnt].dig, A[cnt].sum+=B[i].sum;
cnt++;
}
if (B[i].dig>=MD6){
A[cnt].dig=INF;
A[cnt++].sum=B[i].sum;
}
if (B[i].dig>=MD12){
A[cnt].dig=INF;
A[cnt++].sum=B[i].sum;
}
}
//printf("%d\n",cnt);
//for (i=0;i<cnt;i++)
// printf("%I64d^%d\n",A[i].dig,A[i].sum);
for (i=0;i<cnt;i++)
maxx=max(maxx,A[i].sum);
printf("%d\n",maxx);
ANS.h=1; ANS.a[1]=1;
for (i=0;i<cnt;i++)
if (A[i].sum==maxx)
ANS = (ANS+ANS);
ANS.a[1]--;
for (i=ANS.h;i>0;i--)
printf("%d",ANS.a[i]);
printf("\n");
}
int main(){
init();
scanf("%d",&n);
work1();
work2();
return 0;
}