【BZOJ3667】Rabin-Miller算法

Description

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位长整形范围内。

Source

这题有毒
明明是裸的Pollard_rho
结果出题人强行卡常数
T了无数次后交了黄学长代码

↓:这是我从4253粘贴出来结果TLE的代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
#define MAXN 320010
#define Abs(x)  ((x)>0?(x):-(x))
#define RAND (LL)((LL)rand()*(LL)rand())%p
using namespace std;
const int TEST_NUM=5;
int T;
LL n,maxn;
LL fac[64],top;
inline LL Mult(LL x,LL n,LL P)
{
    LL ret=0;
    for (LL i=n;i;i>>=1,x=(x<<1)%P)
        if (i&1)    ret+=x%P,ret%=P;ret=(ret+P)%P;
    return (ret+P)%P;
}
inline LL Pow(LL x,LL n,LL P)
{
    LL ret=1;
    for (LL i=n;i;i>>=1,x=Mult(x,x,P))
        if (i&1)    ret=Mult(ret,x,P);
    return (ret+P)%P;
}
inline bool check(LL a,LL n,LL x,LL t)
{
    LL ret=Pow(a,x,n),last=ret;
    for (LL i=1;i<=t;i++)
    {
        ret=Mult(ret,ret,n);
        if (ret==1&&last!=1&&last!=n-1) return 0;
        last=ret;
    }
    return (ret==1);
}
inline bool Miller_rabin(LL n)
{
    LL x=n-1,RANDNUM,t=0;
    if (n<=2)    return (n==2);
    if (!(n&1)) return 0;
    if (!(x&1)) x>>=1,t++;
    for (int i=1;i<=TEST_NUM;i++)
    {
        RANDNUM=rand()%(n-2)+2;
        if (!check(RANDNUM,n,x,t))  return 0;
    }
    return 1;
}
inline LL gcd(LL a,LL b)
{
    return !b?a:gcd(b,a%b);
}
inline LL Pollard_rho(LL p)
{
    LL i=1,k=2,x,y,c,ret;
    c=RAND;y=x=RAND;
    while (1)
    {
        i++;x=(Mult(x,x,p)+c)%p;ret=gcd(Abs(y-x),p);
        if (ret!=1) return ret;
        if (i==k)   y=x,k<<=1;
    }
}
inline void get_fac(LL n)
{
    LL minn;
    bool flag=Miller_rabin(n);
    if (flag)   maxn=max(maxn,n);
    else
    {
        minn=Pollard_rho(n);
        while (minn==n) minn=Pollard_rho(n);
        get_fac(minn);get_fac(n/minn);
    }
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        cin>>n;maxn=0;
        if (Miller_rabin(n))    puts("Prime");
        else    get_fac(n),cout<<maxn<<endl;
    }
}

↓:这是黄学长的AC代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<vector>
#define ll long long 
#define inf 1000000000
using namespace std;
ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
ll gcd(ll a,ll b)
{
    return b==0?a:gcd(b,a%b);
}
int n;
ll x,mx;
vector<ll> q;
ll mul(ll a,ll b,ll p)
{
    ll tmp=(a*b-(ll)((long double)a/p*b+1e-8)*p);
    return tmp<0?tmp+p:tmp;
}
ll pow(ll a,ll b,ll p)
{
    ll ans=1;a%=p;
    for(ll i=b;i;i>>=1,a=mul(a,a,p))
        if(i&1)ans=mul(ans,a,p);
    return ans;
}
bool check(ll a,ll n,ll r,ll s)
{
    ll ans=pow(a,r,n),p=ans;
    for(int i=1;i<=s;i++)
    {
        ans=mul(ans,ans,n);
        if(ans==1&&p!=1&&p!=n-1)return 1;
        p=ans;
    }
    if(ans!=1)return 1;
    return 0;
}
bool MR(ll n)
{
    if(n<=1)return 0;
    if(n==2)return 1;
    if(n%2==0)return 0;
    ll r=n-1,s=0;
    while(r%2==0)r/=2,s++;
    for(int i=0;i<10;i++)
        if(check(rand()%(n-1)+1,n,r,s))
            return 0;
    return 1;
}
ll rho(ll n,ll c)
{
    ll k=2,x=rand()%n,y=x,p=1;
    for(ll 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(ll n)
{
    if(n==1)return;
    if(MR(n)){mx=max(n,mx);return;}
    ll t=n;
    while(t==n)t=rho(n,rand()%(n-1)+1);
    solve(t);
    solve(n/t);
}
int main()
{
    n=read();
    while(n--)
    {
        x=read();
        mx=0;
        solve(x);
        if(mx==x)puts("Prime");
        else printf("%lld\n",mx);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值