POJ 1811 Prime Test(费马小定理+二次探测定理)

素数的测试:

费尔马小定理:如果p是一个素数,且0<a<p,则a^(p-1)%p=1.

利用费尔马小定理,对于给定的整数n,可以设计素数判定算法,通过 计算d=a^(n-1)%n来判断n的素性,当d!=1时,n肯定不是素数,当d=1时,n   很可能是素数.

二次探测定理:如果n是一个素数,且0<x<p,则方程x^2%p=1的解为:x=1或    x=p-1.

利用二次探测定理,可以再利用费尔马小定理计算a^(n-1)%n的过程 中增加对整数n的二次探测,一旦发现违背二次探测条件,即得出n不是素数的结论.

如果n是素数,则(n-1)必是偶数,因此可令(n-1)=m*(2^q),其中m是正奇数(若n是偶数,则上面的m*(2^q)一定可以分解成一个正奇数乘以2的k次方的形式),q是非负整数,考察下面的测试:

序列:

a^m%n; a^(2m)%n; a^(4m)%n; …… ;a^(m*2^q)%n

把上述测试序列叫做Miller测试,关于Miller测试,有下面的定理:

定理:若n是素数,a是小于n的正整数,则n对以a为基的Miller测试,结果为真.

Miller测试进行k次,将合数当成素数处理的错误概率最多不会超过4^(-k).

参考博客:http://blog.sina.com.cn/s/blog_6f71bea30100okag.html

PS:需要人品啊。

Prime Test

Time Limit: 6000MS   Memory Limit: 65536K
Total Submissions: 29406   Accepted: 7479
Case Time Limit: 4000MS

Description

Given a big integer number, you are required to find out whether it‘s a prime number.

Input

The first line contains the number of test cases T (1 <= T <= 20 ), then the following T lines each contains an integer number N (2 <= N < 254).

Output

For each test case, if N is a prime number, output a line containing the word "Prime", otherwise, output a line containing the smallest prime factor of N.

Sample Input

2
5
10

Sample Output

Prime
2
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <time.h>
#include <stack>
#include <map>
#include <set>
#define eps 1e-8
#define M 1000100
///#define LL long long
#define LL __int64
#define INF 0x3f3f3f
#define PI 3.1415926535898
#define mod 1000000007
#define MAX (pow(2.0, 60))

#define TIME 12
#define C 240

const int maxn = 110;

using namespace std;

LL Min;

LL gcd(LL x, LL y)
{
    if(y == 0) return x;
    return gcd(y, x%y);
}

LL mod_mult(LL a, LL b, LL n) ///计算(a*b) mod n
{
    LL s = 0;
    a = a % n;
    while (b)
    {
        if (b & 1)
        {
            s += a;
            if (s >= n)
                s -= n;
        }
        a = a << 1;
        if (a >= n)
            a -= n;
        b = b >> 1;
    }

    return s;
}

LL mod_exp(LL a, LL b, LL n) ///计算(a^b) mod n
{
    LL d = 1;
    a = a % n;
    while (b >= 1)
    {
        if (b & 1) d = mod_mult(d, a, n);
        a = mod_mult(a, a, n);
        b = b >> 1;
    }
    return d;
}

bool Wintess(LL a, LL n) ///以a为基对n进行Miller测试并实现二次探测
{
    LL m, x, y;
    int i, j = 0;
    m = n - 1;
    while (m % 2 == 0) ///计算(n-1)=m*(2^j)中的j和m,j=0时m=n-1,不断的除以2直至n为奇数
    {
        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 true; ///返回true时,n是合数

        x = y;
    }
    if (y != 1)
        return true;
    return false;
}

bool miller_rabin(int times,LL n) ///对n进行s次的Miller测试
{
    LL a;
    int i;
    if (n == 1)
        return false;
    if (n == 2)
        return true;
    if (n % 2 == 0)
        return false;
    srand(time(NULL));
    for (i = 1; i <= times; i++)
    {
        a = rand() % (n - 1) + 1;
        if (Wintess(a, n))
            return false;
    }
    return true;
}

LL Pollard(LL n, int c) ///对n进行因字分解,找出n的一个因子,注意该因子不一定是最小的
{
    LL i, k, x, y, d;
    srand(time(NULL));
    i = 1;
    k = 2;
    x = rand() % n;
    y = x;
    while (true)
    {
        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 get_small(LL n, int c) ///找出最小的素数因子
{
    LL m;
    if(n == 1) return;
    if(miller_rabin(TIME, n))
    {
        if(n < Min) Min = n;
        return;
    }
    m = n;
    ///while(m == n) m = Pollard(n, c--);
    while (m == n) //找出n的一个因子
        m = Pollard(n, c--);
    get_small(m, c);
    get_small(n/m, c);
}
int main()
{
    int T;
    LL n;
    cin >>T;
    while(T--)
    {
        scanf("%I64d",&n);
        Min = MAX;
        if(miller_rabin(TIME, n))
        {
            puts("Prime");
            continue;
        }
        get_small(n, C);
        printf("%I64d\n",Min);
    }
    return 0;
}

时间: 2024-10-21 19:17:13

POJ 1811 Prime Test(费马小定理+二次探测定理)的相关文章

POJ SETI 高斯消元 + 费马小定理

http://poj.org/problem?id=2065 题目是要求 如果str[i] = '*'那就是等于0 求这n条方程在%p下的解. 我看了网上的题解说是高斯消元 + 扩展欧几里德. 然后我自己想了想,就用了高斯消元 + 费马小定理.因为%p是质数,所以很容易就用上了费马小定理,就是在除法的时候用一次就好了.还有就是两个模数相乘还要模一次. #include <cstdio> #include <cstdlib> #include <cstring> #inc

【Lucas定理/费马小定理/中国剩余定理/扩展欧几里得】[BZOJ 1951] 古代猪文

[Description] 求 [Solution] 容易得到, 所以,重点在怎么求 如果是p-1是个质数,我们可以用sqrt(n)的时间枚举所有d,用Lucas定理分别计算求和即可. 但是我们发现p-1=2*3*4679*35617,并不是一个质数,所以Lucas定理不能用了吗?并不,我们可以算出这个合式分别对2.3.4679.35617的模值,写出四个同余方程,再用孙子定理求解即可.注意特判g==p的情况,此时费马小定理不成立,ans=0. [Code] #include<cmath> #

SPOJ DCEPC11B - Boring Factorials 费马小定理

题目链接:http://www.spoj.com/problems/DCEPC11B/ 题目大意:求N!对P取余的结果.P是素数,并且abs(N-P)<=1000. 解题思路:wiki-费马小定理: Fermat's little theorem states that if p is a prime number, then for any integer a, the number a p ? a is an integer multiple of p. In the notation of

hdu-5667 Sequence(矩阵快速幂+费马小定理+快速幂)

题目链接: Sequence Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others) Problem Description Holion August will eat every thing he has found. Now there are many foods,but he does not want to eat all of them at once,so he fi

2018 CCPC网络赛 Dream (费马小定理)

Dream Problem Description Freshmen frequently make an error in computing the power of a sum of real numbers, which usually origins from an incorrect equation (m+n)p=mp+np, where m,n,p are real numbers. Let's call it ``Beginner's Dream''. For instance

hdu6440 Dream 2018CCPC网络赛C 费马小定理+构造

题目传送门 题目大意: 给定一个素数p,让你重载加法运算和乘法运算,使(m+n)p=mp+np,并且 存在一个小于p的q,使集合{qk|0<k<p,k∈Z} 等于集合{k|0<k<p,k∈Z}. 然后输出两个矩阵,第一个矩阵输出i+j的值,第二个矩阵输出i*j的值.(题意好难懂,你们怎么都看懂了!!) 思路: 由费马小定理得到,当p是质数的时候,ap-1 ≡ 1(mod p),两边同乘以a,也就是说当ap和a在取模p的时候相等 所以(m+n)p=m+n=mp+np(乘法为x*x%p

HDU5667——费马小定理

题目链接 ------------恢复内容开始------------ 题目链接:https://vjudge.net/problem/HDU-5667 题目意思:按照递推式求出第n项对p求余的结果(p为质数). Sequence HDU - 5667 Holion August will eat every thing he has found. Now there are many foods,but he does not want to eat all of them at once,s

hdu 4704 Sum (整数和分解+快速幂+费马小定理降幂)

题意: 给n(1<n<),求(s1+s2+s3+...+sn)mod(1e9+7).其中si表示n由i个数相加而成的种数,如n=4,则s1=1,s2=3.                         (全题文末) 知识点: 整数n有种和分解方法. 费马小定理:p是质数,若p不能整除a,则 a^(p-1) ≡1(mod p).可利用费马小定理降素数幂. 当m为素数,(m必须是素数才能用费马小定理) a=2时.(a=2只是题中条件,a可以为其他值) mod m =  *      //  k=

HDU 1098 Ignatius&#39;s puzzle 费马小定理+扩展欧几里德算法

题目大意: 给定k,找到一个满足的a使任意的x都满足 f(x)=5*x^13+13*x^5+k*a*x 被65整除 推证: f(x) = (5*x^12 + 13 * x^4 + ak) * x 因为x可以任意取 那么不能总是满足 65|x 那么必须是 65 | (5*x^12 + 13 * x^4 + ak) 那么就是说 x^12 / 13 + x^4 / 5 + ak / 65 正好是一个整数 假设能找到满足的a , 那么将 ak / 65 分进x^12 / 13 + x^4 / 5中得到