【BZOJ2082】【POI2010】Divine divisor 假的pollard-rho

题目大意:给你m个数ai,定义n=Πmi=1ai。将n分解质因数为Πpkiipi是质数。请输出2max(ki)1,以及存在多少个ki,满足ki=max(ki)

数据范围:m600ai1018

 

这题有一种很显然的做法,采用pollardrho对每个ai分解质因数,然后统计每种质因子出现的次数,最后取个max然后再统计下直接输出。

然而这题卡pollardrho(比如来个9982443532),会TLE

所以要采用一个比较高明的做法。

 

我们先用线性筛筛出[1,106]内的质数。

先用这些质数除以每一个ai,并统计这些质数出现的次数。

处理后的ai存在以下几种情况:

1,是数字1,无需处理。

2,是一个106的质数,我们可以用MillerRabin来判断,处理很简单。

3,是一个106的质数的平方,我们可以先对ai开跟,处理很简单。

4,是多个(其实只能是2个)106的质数的乘积。

对于第4种情况,我们枚举两个不为1aiaj,求它们的最大公约数。

若它们的最大公约数不为1,那么我们就成功地把aiaj给分解了。

没想到吧!!!!!!

然后就没有然后了

 

特别注意,此题的答案可能会很大,需要用高精度计算。

 

复制代码
  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 @   AlphaInf  阅读(328)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示