数论小集合。
题目里第一问本质上要求的其实是 数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; }