BZOJ 4802 rho素数分解

我re了很久,最后,我把随机种子从\(time(NULL)\) 改成了随便一个数,然后就A了
这。。。。

果然,信息学就是玄学。

其实就是\(miller-rabin\)\(rho\)算法的板子。
\(rho\)算法大概也明白了一点。
\(miller-rabin\)发现还是挺容易写的。
然后这题最主要的是一些数论的编程细节。
首先
如果是乘法模运算,换成加法会很稳妥。
然后,如果你很懒,就不必把快速幂写成迭代实现,其实也很简单
当你纠结\(unsigned long long\) 怎么输入的时候,一个\(cin\)就可以救你于水火。
这个随机算法其实和确定算法相比误差极小,所以,不要怂的开1000次测试。实际上20次就够了。

/**************************************************************
    Problem: 4802
    User: rsq
    Language: C++
    Result: Accepted
    Time:344 ms
    Memory:1296 kb
****************************************************************/
 
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<cmath>
#include<vector>
#include<ctime>
#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
 
typedef unsigned long long ULL;
 
ULL Mul(ULL a,ULL b,ULL p)
{
    ULL res=0;
    while(b)
    {
        if(b&1)res=(res+a)%p;
        a=(a+a)%p;b>>=1;
    }
    return res;
}
 
ULL Pow(ULL a,ULL b,ULL Mod)
{
    if(b == 0) return 1;
    ULL ans = Pow(a,b/2,Mod);
    ans = Mul(ans,ans,Mod);
    if(b&1) ans = Mul(ans,a,Mod);
    return ans;
}
 
bool check(ULL a,ULL r,ULL s,ULL Mod) //true为合数,false可能为素 
{
    ULL ans = Pow(a,r,Mod);
    ULL p = ans;
    for(ULL i = 0;i < s;i++){
        ans = Mul(ans,ans,Mod);
        if(ans == 1&&p != 1&&p != Mod-1) return true;
        p = ans;
    }
    if(ans != 1) return true;
    return false;
}
 
bool MR(ULL n)
{
    if(n < 2) return false;
    if(n == 2||n == 3|| n == 5) return true;
    if(n%2 == 0) return false;
    ULL r = n-1;ULL s = 0;
    while(r%2 == 0) r/=2,s++;
    for(int i = 0;i < 50;i++){
        ULL a = (rand()%(n-2)) +1;
        if(check(a,r,s,n)) return false;
    }
    return true;    
}
 
ULL gcd(ULL a,ULL b)
{
    if(b == 0) return a;
    else return gcd(b,a%b);
}
vector<ULL> syz;
set<ULL> S;
ULL rho(ULL c,ULL n)
{
    ULL k = 2,x = rand()%n,y = x,p = 1;
    for(int i = 1;p == 1;i++){
        x = (Mul(x,x,n)+c)%n;
        p = y > x?y-x:x-y;
        p = gcd(n,p);
        if(i == k) y = x,k += k;
    }
    return p;
}
void solve(ULL n)
{
    if(n < 2) return ;
    ULL k = n;
    if(MR(n)){
        if(!S.count(n)){
            syz.push_back(n);
            S.insert(n);    
        }return;}
    ULL t = n;
    while(t == n) t = rho(rand()%(n-1)+1,n);
    solve(t);
    solve(n/t);
}
int main()
{
    srand(233333);
    ULL n;
    cin>>n;
    if(n == 0){printf("0\n");exit(0);}
    ULL ans = n;
    solve(n);
    for(int i = 0;i < syz.size();i++)
        ans = ans/syz[i]*(syz[i]-1);
    cout<<ans<<endl;
    return 0;
}
posted @ 2017-05-17 21:27  rsqppp  阅读(76)  评论(0)    收藏  举报