1. 程式人生 > >【刷題】BZOJ 3667 Rabin-Miller算法

【刷題】BZOJ 3667 Rabin-Miller算法

click solution long 輸出 算法 概率 lap srand template

Input

第一行:CAS,代表數據組數(不大於350),以下CAS行,每行一個數字,保證在64位長整形範圍內,並且沒有負數。你需要對於每個數字:第一,檢驗是否是質數,是質數就輸出Prime
第二,如果不是質數,輸出它最大的質因子是哪個。

Output

第一行CAS(CAS<=350,代表測試數據的組數)
以下CAS行:每行一個數字,保證是在64位長整形範圍內的正數。
對於每組測試數據:輸出Prime,代表它是質數,或者輸出它最大的質因子,代表它是和數

Sample Input

6
2
13
134
8897
1234567654321
1000000000000

Sample Output

Prime
Prime
67
41
4649
5

HINT

數據範圍:

保證cas<=350,保證所有數字均在64位長整形範圍內。

Solution

裸Pollard Rho題

但它不簡單,反而很惡心

不知道為什麽數據那麽強

幾個註意的:

1)乘法要寫快速乘,原理是a%b=a-a/b*b

2)Miller Rabin最好優化

3)有些版本的Pollard Rho是錯的。。。被坑了好久(數學一本通)

這東西本身有概率錯誤,導致調都不知道調哪裏,最後是照著zhou888的代碼一點一點邊改邊交邊調的

技術分享圖片
#include<bits/stdc++.h>
#define ll unsigned long long
const int Count=5;
int base[6]={0,2,3,5,7,61};
ll ans;
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!=-&&(ch<0||ch>9))ch=getchar();
    if(ch==-)w=-1
,ch=getchar(); while(ch>=0&&ch<=9)data=((T)data<<3)+((T)data<<1)+(ch^0),ch=getchar(); x=data*w; } template<typename T> inline void write(T x,char c=\0) { if(x<0)putchar(-),x=-x; if(x>9)write(x/10); putchar(x%10+0); if(c!=\0)putchar(c); } template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);} template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);} inline ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b); } inline ll qmul(ll a,ll b,ll n) { return (a*b-(ll)(((long double)a*b+0.5)/n)*n+n)%n; } inline ll qexp(ll a,ll b,ll n) { ll res=1; while(b) { if(b&1)res=qmul(res,a,n); a=qmul(a,a,n); b>>=1; } return res; } inline bool Miller_Rabin(ll N) { if(N==1||(N>3&&N%6!=1&&N%6!=5))return false; for(register int i=1;i<=4;++i) if(N==base[i])return true; else if(N%base[i]==0)return false; ll p=N-1,A,pre,k=0; while(!(p&1))p>>=1,++k; for(register int i=1;i<=Count;++i) { A=rand()%(N-1)+1; A=qexp(A,p,N); pre=A; for(register int j=1;j<=k;++j) { A=qmul(A,A,N); if(A==1&&pre!=1&&pre!=N-1)return false; pre=A; } if(A!=1)return false; } return true; } inline ll abs(ll x,ll y) { return y>x?y-x:x-y; } inline int Pollard_Rho(ll N,ll C) { ll k=2,x=rand()%N,y=x,d=1; for(register ll i=1;d==1;++i) { x=(qmul(x,x,N)+C)%N; d=gcd(abs(x,y),N); if(i==k)k<<=1ll,y=x; } return d; } inline void solve(ll N) { if(N==1)return ; if(Miller_Rabin(N)) { chkmax(ans,N); return ; } ll p,c=1; while((p=Pollard_Rho(N,c))==N&&c<=N)c++; solve(p);solve(N/p); } int main() { srand(2523452); int T; read(T); while(T--) { ll N; read(N); ans=0; solve(N); if(ans==N)puts("Prime"); else write(ans,\n); } return 0; }
3667 Rabin-Miller算法

【刷題】BZOJ 3667 Rabin-Miller算法