【BZOJ2082】【POI2010】Divine divisor 假的pollard-rho
题目大意:给你$m$个数$a_i$,定义$n=\Pi_{i=1}^{m}a_i$。将$n$分解质因数为$\Pi p_i^{k_i} $,$p_i$是质数。请输出$2^{max(k_i)}-1$,以及存在多少个$k_i$,满足$k_i=max(k_i)$。
数据范围:$m≤600$,$a_i≤10^{18} $。
这题有一种很显然的做法,采用$pollard-rho$对每个$a_i$分解质因数,然后统计每种质因子出现的次数,最后取个$max$然后再统计下直接输出。
然而这题卡$pollard-rho$(比如来个$998244353^2$),会$TLE$。
所以要采用一个比较高明的做法。
我们先用线性筛筛出$[1,10^6]$内的质数。
先用这些质数除以每一个$a_i$,并统计这些质数出现的次数。
处理后的$a_i$存在以下几种情况:
1,是数字$1$,无需处理。
2,是一个$>10^6$的质数,我们可以用$Miller-Rabin$来判断,处理很简单。
3,是一个$>10^6$的质数的平方,我们可以先对$a_i$开跟,处理很简单。
4,是多个(其实只能是$2$个)$>10^6$的质数的乘积。
对于第$4$种情况,我们枚举两个不为$1$的$a_i$和$a_j$,求它们的最大公约数。
若它们的最大公约数不为$1$,那么我们就成功地把$a_i$和$a_j$给分解了。
没想到吧!!!!!!
然后就没有然后了
特别注意,此题的答案可能会很大,需要用高精度计算。
1 #include<bits/stdc++.h> 2 #define L long long 3 #define M 1000005 4 #define R(x) (1+rand()%(x-1)) 5 #define N 3000 6 using namespace std; 7 struct bign{ 8 int a[N+1]; 9 bign(){memset(a,0,sizeof(a));} 10 friend bign operator *(bign a,int b){ 11 int s,g=0; 12 for(int i=N;~i;i--){ 13 s=a.a[i]*b+g; 14 a.a[i]=s%10; g=s/10; 15 } 16 return a; 17 } 18 void minus(){ 19 int s,g=1; 20 for(int i=N;~i;i--){ 21 a[i]-=g; 22 if(a[i]<0){a[i]+=10; g=1;} 23 else return; 24 } 25 } 26 void out(){ 27 int i=0; 28 while(i<N&&a[i]==0) i++; 29 while(i<=N) printf("%d",a[i]),i++; 30 } 31 }a; 32 33 L mul(__int128 x,__int128 y,__int128 MOD){ 34 __int128 ans; 35 ans=x*y%MOD; 36 return ans; 37 } 38 L pow_mod(L x,L k,L MOD){ 39 L ans=1; 40 while(k){ 41 if(k&1) ans=mul(ans,x,MOD); 42 x=mul(x,x,MOD); k>>=1; 43 } 44 return ans; 45 } 46 map<L,int> mp; 47 bool checkprime(L x){ 48 if(x==2) return 1; if(x<2||x%2==0) return 0; 49 int times=20; 50 while(times--){ 51 L base=R(x-1); 52 if(pow_mod(base,x-1,x)!=1) return 0; 53 } 54 return 1; 55 } 56 57 int pri[M]={0},b[M]={0},use=0,is[M]={0}; 58 void pre(){ 59 for(int i=2;i<M;i++){ 60 if(!b[i]) pri[++use]=i; 61 for(int j=1;j<=use&&i*pri[j]<M;j++){ 62 b[i*pri[j]]=1; 63 if(i%pri[j]==0) break; 64 } 65 } 66 } 67 L num[M]={0},sum=0; 68 void chu(L &x){ 69 for(int i=1;i<=use;i++) 70 while(x%pri[i]==0) x/=pri[i],mp[pri[i]]++; 71 } 72 73 int main(){ 74 pre(); 75 int n; scanf("%d",&n); 76 for(int i=1;i<=n;i++){ 77 cin>>num[i];chu(num[i]); 78 if(num[i]==1){is[i]=3; continue;} 79 if(checkprime(num[i])) {is[i]=1;mp[num[i]]++;} 80 L hh=sqrt(((long double)num[i])); 81 if(hh*hh==num[i]) {mp[hh]+=2; is[i]=2;} 82 } 83 for(int i=1;i<=n;i++) if(is[i]!=2) 84 for(int j=i+1;j<=n;j++)if(is[j]!=2){ 85 if(num[i]==num[j]) continue; 86 L gcd=__gcd(num[i],num[j]); 87 if(gcd==1) continue; 88 if(is[i]==0) {mp[gcd]++; mp[num[i]/gcd]++; is[i]=4;} 89 if(is[j]==0) {mp[gcd]++; mp[num[j]/gcd]++; is[j]=4;} 90 } 91 for(int i=1;i<=n;i++) if(is[i]==0){ 92 mp[num[i]]++; 93 mp[-num[i]]++; 94 } 95 map<L,int>::iterator it; 96 int maxn=0,cnt=0; 97 for(it=mp.begin();it!=mp.end();it++) 98 maxn=max(maxn,it->second); 99 printf("%d\n",maxn); 100 for(it=mp.begin();it!=mp.end();it++) 101 if(it->second==maxn) cnt++; 102 a.a[N]=1; 103 while(cnt--) a=a*2; 104 a.minus(); 105 a.out(); 106 }