BZOJ 3667 Rabin-Miller算法

216 篇文章 0 订阅

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

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Miller-Rabin算法~

这个算法就是把一堆近似算法放在一起,各判断一次,把判错的可能性降到几乎为0。

具体做法详见http://blog.csdn.net/thy_asdf/article/details/51347390,我觉得就是代替高精度的那个取模乘法比较有用……抄起来真是累啊~


#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const ll a[]={2,3,5,7,11,13,17,19,23,29};

ll t,n,maxx;

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<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}

ll cheng(ll u,ll v,ll mod)
{
	ll res=(long double)u/mod*v+1e-8;
	res=u*v-mod*res;
	return res<0 ? res+mod:res; 
}

ll mi(ll u,ll v,ll mod)
{
	ll res=1;u%=mod;
	for(;v;v>>=1,u=cheng(u,u,mod)) if(v&1) res=cheng(res,u,mod);
	return res;
}

ll gcd(ll u,ll v)
{
	return v ? gcd(v,u%v):u;
}

bool chec(ll u,ll mod,ll k,ll v)
{
	ll now=mi(u,k,mod),las=now;
	for(int i=1;i<=v;i++)
	{
		now=cheng(now,now,mod);
		if(now==1 && las!=1 && las!=mod-1) return 0;
		las=now;
	}
	return now==1 ? 1:0;
}

bool mr(ll u)
{
	if(u<=1) return 0;
	ll res=u-1,now=0;
	while(!(res&1)) res>>=1,now++;
	for(int i=0;i<9;i++)
	{
		if(u==a[i]) return 1;
		if(!chec(a[i],u,res,now)) return 0;
	}
	return 1;
}

ll chan(ll u,ll v)
{
	ll k=2,x=rand()%u,y=x,p=1;
	for(ll i=1;p==1;i++)
	{
		x=(cheng(x,x,u)+v)%u;
		p=y>x ? y-x:x-y;p=gcd(p,u);
		if(i==k) y=x,k+=k;
	}
	return p;
}

void solve(ll u)
{
	if(u==1) return;
	if(mr(u))
	{
		maxx=max(maxx,u);return;
	}
	ll now=u;
	while(now==u) now=chan(u,rand()%(u-1));
	solve(now);solve(u/now);
}

int main()
{
	srand(20000619);t=read();
	while(t--)
	{
		n=read();maxx=0;solve(n);
		if(n==maxx) puts("Prime");
		else printf("%lld\n",maxx);
	}
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值