// 判断两个数是否互素 boolis_coprime(LL a, LL b, vector<int> prime){ if(a == b) returnfalse; // 如果相等肯定不互素 if(a == 1 || b == 1) returntrue; // 1与任何数互素 if(a % b == 0 || b % a == 0) returnfalse; // 如果可以整除另外一个数,不互素 if(prime[a] == 1 || prime[b] == 1) returntrue; // 不能整除时,有一个是素数则互素 // 剩下就是两个数都是合数的情况 LL ceiling = min(a, b); // 取较小的那个数 for(LL i = 2; i <= ceiling; i ++) { if(prime[i] == 0) continue; if(a % i == 0 && b % i == 0) returnfalse; // 如果有公共素因子,不互素 } returntrue; // 其他情况,互素 }
第三步 计算 ae(modm)
1 2 3 4 5 6 7 8 9 10 11 12
// 模平方重复法(快速幂),求a^e(modm) LL quick_pow(LL a, LL e, LL m){ LL answer = 1, base = a % m; while (e != 0) { if (e & 1) answer = (answer * base) % m; base = (base * base) % m; e >>= 1; } return answer; }
// 对于非奇素数m,用暴力的方法求出所有原根 voidfind_roots(LL m, vector<int> prime, vector<LL> &roots, LL phi_m){ for(LL a = 1; a < m; a ++) { if(is_coprime(a, m, prime)) { // 先判断a、m是否互素 bool flag = true; for(LL e = 1; e < phi_m; e ++) { // 寻找有没有小于φ(m)的e if(quick_pow(a, e, m) == 1) { flag = false; // 找到了,则a不是原根 break; } } if(!flag) continue; if(quick_pow(a, phi_m, m) == 1) { roots.push_back(a); // 如果a^e=1(mod m),是原根 } } } }
// 对于奇素数m,先求出一个原根和m-1的简化剩余系,然后生成所有原根 // 暴力判断出最小的原根g,大部分和find_roots相同 LL find_a_root(LL m, vector<int> prime, LL phi_m){ LL g; for(LL a = 1; a < m; a ++) { if(is_coprime(a, m, prime)) { bool flag = true; for(LL e = 1; e < phi_m; e ++) { if(quick_pow(a, e, m) == 1) { flag = false; break; } } if(!flag) continue; if(quick_pow(a, phi_m, m) == 1) { g = a; printf("找到一个原根g = %lld\n", g); return g; } } } return g; }
// d遍历p-1的一个简化剩余系,那么g^d(mod p)遍历模p的所有原根 voidfind_roots_p(LL m, vector<int> prime, vector<LL> &roots, LL phi_m){ LL g = find_a_root(m, prime, phi_m); vector<LL> sim_m_1; for(LL i = 1; i < m - 1; i ++) { // 暴力求m-1的简化剩余系 if(is_coprime(i, m - 1, prime)) { sim_m_1.push_back(i); } } for(auto d:sim_m_1) { // 由m-1的简化剩余系生成所有原根 roots.push_back(quick_pow(g, d, m)); } sort(roots.begin(), roots.end()); }
给出m的简化剩余系
基础知识-一个原根→简化剩余系&所有原根节中写得应该很清楚了
1 2 3 4 5 6 7
// 由原根计算简化剩余系 voidcal_sim(LL m, LL g, LL phi_m, vector<LL> &sim){ for(LL i = 0; i < phi_m; i ++) { LL ans = quick_pow(g, i, m); sim.push_back(ans); } }