【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 }

 

posted @ 2018-07-03 17:51  AlphaInf  阅读(320)  评论(0编辑  收藏  举报