51nod1186(Miller-Rabin)
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1186
题意:中文题目诶~
思路:miller_rabin模板 (详情可参见: http://blog.csdn.net/s031302306/article/details/51606018)
注意这里的 n 为 1e30,需要用字符串处理
代码:
1 #include <string.h> 2 #include <cstdlib> 3 4 #define MAXL 4 5 #define M10 1000000000 6 #define Z10 9 7 8 const int zero[MAXL - 1] = {0}; 9 10 struct bnum{ 11 int data[MAXL]; // 断成每截9个长度 12 // 读取字符串并转存 13 void read(){ 14 memset(data, 0, sizeof(data)); 15 char buf[32]; 16 scanf("%s", buf); 17 int len = (int)strlen(buf); 18 int i = 0, k; 19 while (len >= Z10){ 20 for (k = len - Z10; k < len; ++k){ 21 data[i] = data[i] * 10 + buf[k] - '0'; 22 } 23 ++i; 24 len -= Z10; 25 } 26 if (len > 0){ 27 for (k = 0; k < len; ++k){ 28 data[i] = data[i] * 10 + buf[k] - '0'; 29 } 30 } 31 } 32 33 bool operator == (const bnum &x){ 34 return memcmp(data, x.data, sizeof(data)) == 0; 35 } 36 37 bnum & operator = (const int x){ 38 memset(data, 0, sizeof(data)); 39 data[0] = x; 40 return *this; 41 } 42 43 bnum operator + (const bnum &x){ 44 int i, carry = 0; 45 bnum ans; 46 for (i = 0; i < MAXL; ++i){ 47 ans.data[i] = data[i] + x.data[i] + carry; 48 carry = ans.data[i] / M10; 49 ans.data[i] %= M10; 50 } 51 return ans; 52 } 53 54 bnum operator - (const bnum &x){ 55 int i, carry = 0; 56 bnum ans; 57 for (i = 0; i < MAXL; ++i){ 58 ans.data[i] = data[i] - x.data[i] - carry; 59 if (ans.data[i] < 0){ 60 ans.data[i] += M10; 61 carry = 1; 62 }else{ 63 carry = 0; 64 } 65 } 66 return ans; 67 } 68 69 // assume *this < x * 2 70 bnum operator % (const bnum &x){ 71 int i; 72 for (i = MAXL - 1; i >= 0; --i){ 73 if (data[i] < x.data[i]){ 74 return *this; 75 } 76 else if (data[i] > x.data[i]){ 77 break; 78 } 79 } 80 return ((*this) - x); 81 } 82 83 bnum & div2(){ 84 int i, carry = 0, tmp; 85 for (i = MAXL - 1; i >= 0; --i){ 86 tmp = data[i] & 1; 87 data[i] = (data[i] + carry) >> 1; 88 carry = tmp * M10; 89 } 90 return *this; 91 } 92 93 bool is_odd(){ 94 return (data[0] & 1) == 1; 95 } 96 97 bool is_zero(){ 98 for (int i = 0; i < MAXL; ++i){ 99 if (data[i]){ 100 return false; 101 } 102 } 103 return true; 104 } 105 }; 106 107 void mulmod(bnum &a0, bnum &b0, bnum &p, bnum &ans){//计算a0*b0%p 108 ans = 0; 109 bnum tmp = a0, b = b0; 110 while (!b.is_zero()){ 111 if (b.is_odd()){ 112 ans = (ans + tmp) % p; 113 } 114 tmp = (tmp + tmp) % p; 115 b.div2(); 116 } 117 } 118 119 void powmod(bnum &a0, bnum &b0, bnum &p, bnum &ans){//计算a0^b0%p 120 bnum tmp = a0, b = b0; 121 ans = 1; 122 while (!b.is_zero()){ 123 if (b.is_odd()){ 124 mulmod(ans, tmp, p, ans); 125 } 126 mulmod(tmp, tmp, p, tmp); 127 b.div2(); 128 } 129 } 130 131 bool MillerRabinTest(bnum &p, int iter){ 132 int i, small = 0, j, d = 0; 133 for (i = 1; i < MAXL; ++i){ 134 if (p.data[i]){ 135 break; 136 } 137 } 138 if (i == MAXL){ 139 // small integer test 140 if (p.data[0] < 2){ 141 return false; 142 } 143 if (p.data[0] == 2){ 144 return true; 145 } 146 small = 1; 147 } 148 if (!p.is_odd()){ 149 return false; // even number 150 } 151 bnum a, s, m, one, pd1; 152 one = 1; 153 s = pd1 = p - one; 154 while (!s.is_odd()){ 155 s.div2(); 156 ++d; 157 } 158 159 for (i = 0; i < iter; ++i){ 160 a = rand(); 161 if (small){ 162 a.data[0] = a.data[0] % (p.data[0] - 1) + 1; 163 }else{ 164 a.data[1] = a.data[0] / M10; 165 a.data[0] %= M10; 166 } 167 if (a == one){ 168 continue; 169 } 170 171 powmod(a, s, p, m); 172 173 for (j = 0; j < d && !(m == one) && !(m == pd1); ++j){ 174 mulmod(m, m, p, m); 175 } 176 if (!(m == pd1) && j > 0){ 177 return false; 178 } 179 } 180 return true; 181 } 182 183 int main(void){ 184 bnum x; 185 x.read(); 186 puts(MillerRabinTest(x, 5) ? "Yes" : "No"); 187 return 0; 188 }
对于long long范围:
1 #include <stdio.h> 2 #include <iostream> 3 #include <cstdlib> 4 #define ll long long 5 using namespace std; 6 7 //利用二进制计算a*b%mod 8 ll multi_mod(ll a, ll b, ll mod){ 9 ll ans = 0LL; 10 a %= mod; 11 while(b){ 12 if (b & 1LL) ans = (ans+a)%mod; 13 b >>= 1LL; 14 a = (a+a)%mod; 15 } 16 return ans; 17 } 18 19 //计算a^b%mod 20 ll power_mod(ll a, ll b, ll mod){ 21 ll ans = 1LL; 22 a %= mod; 23 while(b){ 24 if(b & 1LL) ans = multi_mod(ans, a, mod); 25 b >>= 1LL; 26 a = multi_mod(a, a, mod); 27 } 28 return ans; 29 } 30 31 //Miller-Rabin测试,测试n是否为素数 32 bool miller_rabin(ll n, int repeat){ 33 if (2LL == n || 3LL == n) return true; 34 if (n%2==0 || n%3==0 || n%5==0) return false; 35 36 //将n分解为2^s*d 37 ll d = n - 1LL; 38 int s = 0; 39 while(!(d & 1LL)){ 40 s++; 41 d >>= 1LL; 42 } 43 // srand((unsigned)time(0)); 44 for(int i=0; i<repeat; ++i){//重复repeat次 45 ll a = rand() % (n - 3) + 2;//取一个随机数,[2,n-1) 46 ll x = power_mod(a, d, n); 47 ll y = 0LL; 48 for(int j=0; j<s; ++j){ 49 y = multi_mod(x, x, n); 50 if (1LL == y && 1LL != x && n-1LL != x) return false; 51 x = y; 52 } 53 if (1LL != y) return false; 54 } 55 return true; 56 } 57 58 int main(void){ 59 ll n; 60 cin >> n; 61 if(miller_rabin(n, 5)) cout << "Yes" << endl; 62 else cout << "No" << endl; 63 return 0; 64 }
我就是我,颜色不一样的烟火 --- geloutingyu