Miller Rabin 算法验证素数 USACO 1.5 回文质数
2015-10-26 22:07
330 查看
题意:给定a, b,从小到大输出区间[a, b]中所有的回文质数。当一个质数反过来之后与之前相同时为回文质数。
其实这道题不必用MR算法,直接暴力sqrt(n)判断一个数是否为质数可过。
先说这道题,为什么要用到判断一个数是否为质数。a, b的范围是1亿,所以先筛素数再判断每个素数是否回文数是行不通的。所以要先生成所有的回文数,判断它是否为素数。而且,生成回文数的过程还需要一点点优化:
1.回文数长度必须为奇数,偶数长度回文数仅11为质数,其他均能被11整除。
2.回文数的首位(末位)不得为偶数,不得为5。
然后根据区间[a, b]生成长度为3、5、7的回文数,sqrt(n)判断其是否为素数即可,到这里就可以结束了。
然而通过这道题了解到了Miller Rabin算法,就去看了看。
简述一下就是:
如果n是一个奇素数,那么设n-1 = 2^s * r;
对于一个满足gcd(a, n) == 1的a,若n为奇素数,那么必然存在:
a^r % n == 1 或 a^(2^j * r) % n == n-1 ( j ∈ [0, s-1] )。
不过,仍然有一些合数满足以上过程,所以MR算法就有一定的误判可能性。所以实际操作通常找多个a来判断,减小误判概率。
我这里,只是十分浅显地叙述了一下这个算法的实现过程,理论基础、误判概率计算等等详细内容见百度百科。
Miller Rabin算法:百度百科, wiki百科
其实这道题不必用MR算法,直接暴力sqrt(n)判断一个数是否为质数可过。
先说这道题,为什么要用到判断一个数是否为质数。a, b的范围是1亿,所以先筛素数再判断每个素数是否回文数是行不通的。所以要先生成所有的回文数,判断它是否为素数。而且,生成回文数的过程还需要一点点优化:
1.回文数长度必须为奇数,偶数长度回文数仅11为质数,其他均能被11整除。
2.回文数的首位(末位)不得为偶数,不得为5。
然后根据区间[a, b]生成长度为3、5、7的回文数,sqrt(n)判断其是否为素数即可,到这里就可以结束了。
然而通过这道题了解到了Miller Rabin算法,就去看了看。
简述一下就是:
如果n是一个奇素数,那么设n-1 = 2^s * r;
对于一个满足gcd(a, n) == 1的a,若n为奇素数,那么必然存在:
a^r % n == 1 或 a^(2^j * r) % n == n-1 ( j ∈ [0, s-1] )。
不过,仍然有一些合数满足以上过程,所以MR算法就有一定的误判可能性。所以实际操作通常找多个a来判断,减小误判概率。
我这里,只是十分浅显地叙述了一下这个算法的实现过程,理论基础、误判概率计算等等详细内容见百度百科。
Miller Rabin算法:百度百科, wiki百科
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; typedef long long L; int a, b; int t[5] = {2,3,5,7,11}, A[5] = {2,3,7,61,24251}; int Create(int x, int mid) { int res = x*10+mid; while(x) res = res*10+x%10, x /= 10; return res; } L pow(L x, int y, L mod) { if(y == 0) return 1; if(y == 1) return x; L t = pow(x, y>>1, mod); if(y&1) return (t*x%mod)*t%mod; return t*t%mod; } bool Prime(int x) { int s = 0, r, mod = x--, i, j; while(!(x&1)) s++, x>>=1; r = x; for(i = 0; i < 5; i++) { if(pow((L)A[i], r, (L)mod) == 1) continue; L res = pow((L)A[i], r, (L)mod); for(j = 0; j < s; j++) { if(res == mod-1) break; res = res*res%mod; } if(j == s) return 0; } return 1; } void Initialize() { scanf("%d %d", &a, &b); for(int i = 0; i < 5; i++) if(a <= t[i]) printf("%d\n", t[i]); } void Create_num(int len, int ed, int x) { if(len == ed) { for(int i = 0; i <= 9; i++) { int num = Create(x, i); if(a <= num && num <= b && Prime(num)) printf("%d\n", num); } return ; } if(ed) for(int i = 0; i <= 9; i++) Create_num(len, ed+1, x*10+i); else for(int i = 1; i <= 9; i+=2) if(i != 5) Create_num(len, ed+1, x*10+i); } int main() { Initialize(); if(a <= 999 && b >= 100) Create_num(1, 0, 0); if(a <= 99999 && b >= 10000) Create_num(2, 0, 0); if(a <= 9999999 && b >= 1000000) Create_num(3, 0, 0); return 0; }
相关文章推荐
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例
- PHP实现克鲁斯卡尔算法实例解析
- C#获取关键字附近文字算法实例