poj1811 Prime Test 素数测试 +整数分解+分治

题目链接:http://poj.org/problem?id=1811

题目意思:给出一个数判断是否是素数,若不是素数,求出最小质因子



费马小定理:若p是素数,则有 a^(p-1) =1 (mod p ) ,       1<=a<=n-1。

二次探测定理: 若p是素数,对于   0<x<p ,有   x^2= 1 ( mod p)   的解  x=1, p-1。

首先是素数的测试,根据费马小定理和二次探测定理对素数进行测试


整数分解: n为待分解数,

1  找出两个数x,y ,求d=gcd( y - x, n)

2 若1<d< n 返回d; 若y==x 返回n;


当分解出一个约数之后,用分治的方法求出最小质因子

代码如下: 


//============================================================================
// Name        : poj1811.cpp
// Author      : ssslpk
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<cstdlib>

#define int64 long long
#define TIME 12
#define inf 1e10
using namespace std;

int64 minn;

int64 gcd(int64 a,int64 b){return b? gcd(b,a%b):a;}

int64 mod_mult(int64 a,int64 b,int64 n)// 求 (a * b)%n
{
	int64 s=0;
	a=a%n;
	while(b)
	{
		if(b&1) s=(s+a)%n;
		a<<=1;
		a=a%n;
		b>>=1;
	}
	return s;
}
int64 mod_exp(int64 a,int64 b,int64 n)// 求(a ^ b)%n
{
	int64 d=1;a%=n;
	while(b>=1)
	{
		if(b&1)d=mod_mult(d,a,n);
		a=mod_mult(a,a,n);
		b>>=1;
	}
	return d;
}

bool witness(int64 a, int64 n) 
{
    int64 m, x, y;
    int64 i, j = 0;
    m = n - 1;
    while (m % 2 == 0) 
    {
        m = m >> 1;
        j++;
    }
    x = mod_exp(a, m, n);
    for (i = 1; i <= j; i++) {
        y = mod_exp(x, 2, n);
        if ((y == 1) && (x != 1) && (x != n - 1))
            return false; 
        x = y;
    }
    return y==1;
}

bool miler(int64 n)
{
	if(n==2)return true;
	if(n%2==0 || n==1)return false;
	for(int i=0;i<TIME;i++)
	{
		int64 x=rand()%(n-1)+1;
	//	int64 x=rand()*(n-2)%RAND_MAX+1;
		if(! witness(x,n))return false;
	}
	return true;
}

int64 Pollard(int64 n,int64 c)
{
	int64 i,k,x,y,d;
	srand(time(NULL));
	i=1;k=2;
	x=rand()%n;
	y=x;
	while(1)
	{
		i++;
		x=(mod_mult(x,x,n)+c)%n;
		d=gcd(y-x,n);
		if(d>1 && d<n )return d;
		if(y==x)return n;
		if(i==k)
		{
			y=x;
			k=k<<1;
		}
	}
}

void find_min(int64 n,int64 c)
{
	if(n==1)return;
	if(miler(n))
	{
		if(n<minn)minn=n;
		return ;
	}
	int64 m=Pollard(n,c--);
	find_min(m,c);
	find_min(n/m,c);

}
int main()
{
	int cas;
	scanf("%d",&cas);
	while(cas--)
	{
		int64 n;
		scanf("%lld",&n);
		if(miler(n))printf("Prime\n");
		else
		{
			minn=inf;
			find_min(n,240);
			printf("%lld\n",minn);
		}
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值