码迷,mamicode.com
首页 > 其他好文 > 详细

基础的数论知识

时间:2015-03-31 10:29:52      阅读:111      评论:0      收藏:0      [点我收藏+]

标签:

 

1) 素数

Theorem 素数有无限多个

Proof. 若存在最大素数P_max , 设 X = (P_1 * P_2 …… * P_max) + 1,此时如果X为素数, 则X > P_max, 矛盾, 如果X为合数, 则必存在它的一个素因子 P_X 且 P_X > P_max, 矛盾。

 

Theorem

 技术分享

显然是在越大的范围内分布得越稀疏的。

 

素数的判定

暴力的方法即枚举每个小于n的数位约数, 简单的优化即 枚举 2~sqrt(n) 的所有质数。

由于一些伪素数令费马小定理的逆定理不成立, 而去背一张伪素数表又不是很优美, miller-rabin 算法随之产生。

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

强伪素数
设n是一个大于4的奇整数,s和t是使得(n-1)=2^s*t的正整数,其中t为奇数,设B(n)是如下定义的整数集合:
a属于集合B(n)当且仅当2≤a≤n-2且

1: a^tmodn=1
2: 存在整数i,0<=i<s满足a^((2^i)*t) mod n=n-1
当n为素数时, 任意a在2和n-1中,均有a属于集合B(n)
当n为合数时,若a属于集合B(n),则称n为一个以a为底(基)的强伪素数,称a为n素性的强伪证据。
n为素数,说明它对所有底均为强伪素数

 

Btest(a,n){
//n为奇数,返回true。即返回真说明n是强伪素数
   s←0; t ←n-1; //t开始为偶数
     repeat
         s++;t ← t÷2;
   until t mod 2 = 1; //n-1=2st     t为奇数
          x ←at mod n;
   if x=1 or x=n-1 then return true;    //满足①or②。
   for i ←1 to s-1 do{
         x ←x2 mod n;
         if x=n-1 then return true; //满足②,
   }
   return false;}

 


 

通过这一定义则发现,小于1000的奇合数中,随机选到一个强伪证据的概率小于1%
更重要的是,对任一奇合数,强伪证据比例都很小
所以,我们可以多次运行下面的算法,就可把错误概率降低我们可控制的范围


MillRab(n) { //奇n>4,返回真时表示素数,假表示合数
a←uniform(2..n-2);
return Btest(a,n);   //测试n是否为强伪素数
}//该算法是3/4-正确,偏假的。


 


RepeatMillRob(n,k){
      for i ←1 to k do
    if MillRob(n) =false then
     return false; //一定是合数
    return true;
}

 

虽然miller-rabin 是一个随机性算法, 但是取前9个素数就可以保证在 10^18范围内的正确性了。

代码很简单

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define ll long long
using namespace std;
int t, prim[15] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23};
ll u;
ll mypow(ll x, ll k, ll mod){
	ll ret = 1;
	while(k){
		if(k & 1) (ret *= x) %= mod;
		(x *= x) %= mod;
		k >>= 1;
	}return ret;
}
bool MR(ll a, ll n){
	if(a >= n) return 1;
	ll w = mypow(a, u, n);
	if(w == 1) return 1;
	for(int i = 0; i < t; i ++){
		if(w == n - 1) return 1;
		(w *= w) %= n;
	} return 0;
}
bool pd(ll n){
	if(n == 2) return 1;
	if(n < 2 || (!(n & 1))) return 0;
	t = 0; u = n - 1;
	while((u & 1) == 0) u >>= 1, t ++;
	for(int i = 1; i <= 9; i ++) if(!MR(prim[i], n)) return 0;
	return 1;
}
int main(){
	int N; 
	while(scanf("%d", &N) != EOF){
		int cnt = 0;
		for(int i = 1; i <= N; i ++){
			ll x; scanf("%I64d", &x);
			if(pd(x)) cnt ++;
		}
		printf("%d\n", cnt);
	}
	return 0;
}

  

 

基础的数论知识

标签:

原文地址:http://www.cnblogs.com/lixintong911/p/4380039.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!