poj 1811解题报告——关于大数的素数鉴定与质因数分解
2013-08-31 22:18
337 查看
题目来源:http://poj.org/problem?id=1811
题目描述:题意十分简单,不多说。。
题目分析:
这是一道数论的经典题!
首先介绍两个传说中的随机算法。。
Millier-Rabin
根据费马小定理,如果p是素数,则a^(p-1)≡1(mod p)对所有的a∈[1,n-1]成立。所以如果在[1,n-1]中随机取出一个a,发现不满足费马小定理,则证明n必为合数。
为了计算a^(n-1)modn,我们把n-1分解为u*2^t的形式,其中t>=1且u是奇数;亦即,n-1的二进制表示是奇数u的二进制表示后面跟上t个零。因此,a^(n-1)≡(a^u)^(2^t)(mod n),所以可以通过先计算a^u mod n,然后对结果连续平方t次来计算a^(n-1)
mod n。
其中还用到定理,如果对模n存在1的非平凡平方根,则n是合数。(如果一个数x满足方程x^2≡1 (mod n),但x不等于对模n来说1的两个‘平凡’平方根:1或-1,则x是对模n来说1的非平凡平方根)。
Pollard rho
原理:设n为待分解的大整数,用某种方法生成a和b,计算p=gcd(a-b,n),直到p不为1或a,b出现循环时为止,若p=n,则说明n是一个素数,否则p为n的一个约数。
算法步骤:选取一个小的随机数x1,迭代生成x[i] = x[i-1]^2+c,一般去c=1,若序列出现循环则退出,计算p=gcd(x[i-1]-x[i],n),若p=1则返回上一步继续迭代,否则跳出迭代过程。若p=n,则n为素数,否则p为n的一个约数,并递归分解p和n/p。
可以在θ(sqrt(p))的期望时间内找到n的一个小因子p。但对于因子很少,因子值很大的大整数n,该方法依然不是很有效。
到这里应该就会做了,不会的直接看代码吧。。写的注释很详细的
代码实现:
题目描述:题意十分简单,不多说。。
题目分析:
这是一道数论的经典题!
首先介绍两个传说中的随机算法。。
Millier-Rabin
根据费马小定理,如果p是素数,则a^(p-1)≡1(mod p)对所有的a∈[1,n-1]成立。所以如果在[1,n-1]中随机取出一个a,发现不满足费马小定理,则证明n必为合数。
为了计算a^(n-1)modn,我们把n-1分解为u*2^t的形式,其中t>=1且u是奇数;亦即,n-1的二进制表示是奇数u的二进制表示后面跟上t个零。因此,a^(n-1)≡(a^u)^(2^t)(mod n),所以可以通过先计算a^u mod n,然后对结果连续平方t次来计算a^(n-1)
mod n。
其中还用到定理,如果对模n存在1的非平凡平方根,则n是合数。(如果一个数x满足方程x^2≡1 (mod n),但x不等于对模n来说1的两个‘平凡’平方根:1或-1,则x是对模n来说1的非平凡平方根)。
Pollard rho
原理:设n为待分解的大整数,用某种方法生成a和b,计算p=gcd(a-b,n),直到p不为1或a,b出现循环时为止,若p=n,则说明n是一个素数,否则p为n的一个约数。
算法步骤:选取一个小的随机数x1,迭代生成x[i] = x[i-1]^2+c,一般去c=1,若序列出现循环则退出,计算p=gcd(x[i-1]-x[i],n),若p=1则返回上一步继续迭代,否则跳出迭代过程。若p=n,则n为素数,否则p为n的一个约数,并递归分解p和n/p。
可以在θ(sqrt(p))的期望时间内找到n的一个小因子p。但对于因子很少,因子值很大的大整数n,该方法依然不是很有效。
到这里应该就会做了,不会的直接看代码吧。。写的注释很详细的
代码实现:
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<time.h> #include<iostream> #include<algorithm> using namespace std; //**************************************************************** // Miller_Rabin 算法进行素数测试 //速度快,而且可以判断 <2^63的数 //**************************************************************** const int S=20;//随机算法判定次数,S越大,判错概率越小 //计算 (a*b)%c. a,b都是long long的数,直接相乘可能溢出的 // a,b,c <2^63 //计算A*B的时候,也可以将B化成2^n相加的式子。 //于是,我们可以将a*b mod c转换成[a*(2^b0+2^b1+……2^bn)] mod c=[a*2^b0+a*2^b1+……a*2^bn] mod c。 //利用公式(a+b)mod c=[(a mod c)+(b mod c)]mod c这个公式进行运算。 long long mult_mod(long long a,long long b,long long c) { a%=c; b%=c; long long ret=0; while(b) { if(b&1) { ret+=a; ret%=c; } a<<=1; if(a>=c)a%=c; b>>=1; } return ret; } //计算 x^n %c,类似于计算a^b long long pow_mod(long long x,long long n,long long mod)//x^n%c { if(n==1)return x%mod; x%=mod; long long tmp=x; long long ret=1; while(n) { if(n&1) ret=mult_mod(ret,tmp,mod); tmp=mult_mod(tmp,tmp,mod); n>>=1; } return ret; } //以a为基,n-1=x*2^t a^(n-1)=1(mod n) 验证n是不是合数 //一定是合数返回true,不一定返回false bool check(long long a,long long n,long long x,long long t) { long long ret=pow_mod(a,x,n); long long last=ret; for(int i=1; i<=t; i++) { ret=mult_mod(ret,ret,n); if(ret==1&&last!=1&&last!=n-1) return true;//合数 last=ret; } if(ret!=1) return true; return false; } // Miller_Rabin()算法素数判定 //是素数返回true.(可能是伪素数,但概率极小) //合数返回false; bool Miller_Rabin(long long n) { if(n<2)return false; if(n==2)return true; if((n&1)==0) return false;//偶数 long long x=n-1; long long t=0; while((x&1)==0) { x>>=1; t++; } for(int i=0; i<S; i++) { long long a=rand()%(n-1)+1;//rand()需要stdlib.h头文件 if(check(a,n,x,t)) return false;//合数 } return true; } //************************************************ //pollard_rho 算法进行质因数分解 //************************************************ long long factor[100];//质因数分解结果(刚返回时是无序的) int tol;//质因数的个数。数组小标从0开始 long long gcd(long long a,long long b) { if(a==0)return 1;//??????? if(a<0) return gcd(-a,b); while(b) { long long t=a%b; a=b; b=t; } return a; } long long Pollard_rho(long long x,long long c) { long long i=1,k=2; long long x0=rand()%x; long long y=x0; while(1) { i++; x0=(mult_mod(x0,x0,x)+c)%x; long long d=gcd(y-x0,x); if(d!=1&&d!=x) return d; if(y==x0) return x; if(i==k) { y=x0; k+=k; } } } //对n进行素因子分解 void findfac(long long n) { if(Miller_Rabin(n))//素数 { factor[tol++]=n; return; } long long p=n; while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1); findfac(p); findfac(n/p); } int main() { //srand(time(NULL));//需要time.h头文件//POJ上G++不能加这句话 long long n; int t; scanf("%d",&t); while(t--) { scanf("%I64d",&n); tol=0; if(Miller_Rabin(n)) { printf("Prime\n"); continue; } findfac(n); long long min = n; for(int i=0; i<tol; i++) { if(factor[i] < min) min = factor[i]; } printf("%I64d\n",min); } return 0; }
相关文章推荐
- poj 1811解题报告
- poj 1811 随机素数和大数分解(模板)
- POJ 2739(连续素数和) 解题报告
- POJ 1811 解题报告
- POJ 3101 Astronomy 解题报告(大数乘法+分数最小公倍数)
- 【原】 POJ 2262 Goldbach's Conjecture 筛素数 解题报告
- poj 2689解题报告(区间筛素数,经典)
- POJ 2689 Prime Distance 解题报告(素数筛)
- 【POJ1182】食物链,思路+数据+代码,可能是史上关于这道题最详细的解题报告
- POJ 1811 Prime Test【素数判定与大数分解】
- POJ 2191 Mersenne Composite Numbers 解题报告(大数因式分解)
- 数学#素数判定Miller_Rabin+大数因数分解Pollard_rho算法 POJ 1811&2429
- 【原】 POJ 2739 Sum of Consecutive Prime Numbers 筛素数+积累数组 解题报告
- POJ 1811 Prime Test(大素数判定+质因数分解)
- POJ 2773 Happy 2006 解题报告(容斥原理+质因数分解)
- poj1811 + hdu4344 (素数测试及大数分解)
- poj 2389 解题报告 大数乘法
- POJ 2429 GCD & LCM Inverse 解题报告(大数因式分解)
- poj 1811 随机素数和大数分解(模板)
- poj 1811 Prime Test【 随机素数测试与大数分解】