目录
BASIC KNOWLEDGE
快速幂(mod)
int fp_mod(int a, int n, int m) { int ans = 1, temp = a; while (n) { if (n & 1) { ans = ans * temp % m; } temp = temp * temp % m; n >>= 1; } return ans; }
乘法取模(mod)
int multi(int a, int b, int m) { int ans = 0; while (b) { if (b & 1) { ans = (ans + a) % m; } a = (a << 1) % m; b >>= 1; } return ans; }
费马小定理
假如 是一个整数, 是一个质数,那么 是的倍数,可以表示为
如果不是的倍数,这个定理也可以写成
欧拉函数
int phi(int n) { int i, res = 1; for (i = 2; i * i <= n; i++) { if (n % i == 0) { res = res * (i - 1); n = n / i; while (n % i == 0) { res = res * i; n = n / i; } } if (n == 1) { break; } } if (n > 1) { res = res * (n - 1); } return res; }
欧拉筛法
void gen(int n, vector<int> &primelist, bool check[]) { memset(check, 0, sizeof(bool) * n); for (int i = 2, u; i < n; i++) { if (!check[i]) { primelist.push_back(i); } for (int j = 0; j < primelist.size() && i * primelist[j] < n; j++) { u = i * primelist[j]; check[u] = 1; if (i % primelist[j] == 0) { break; } } } }
P1 Sum
费马小定理 快速幂取模PROBLEM
HDU – 4704
ANALYSIS
个球放到个桶的方案数(mod 1e9+7)。
费马小定理降幂。
SOLUTION
#include <iostream> #include <cstdio> using namespace std; constexpr long long mod = 1e9 + 7; long long fp_mod(long long a, long long n, long long m) { long long ans = 1, temp = a; while (n) { if (n & 1) { ans = ans * temp % m; } temp = temp * temp % m; n >>= 1; } return ans; } int main() { for (string s; cin >> s;) { long long u = 0, x = 1; for (auto it = s.begin(), e = s.end(); it != e; ++it) { u *= 10; u += *it - '0'; u %= mod - 1; } u = (u - 1 + mod - 1) % (mod - 1); cout << fp_mod(2, u, mod) << endl; } return 0; }
P2 2^x mod n = 1
费马小定理 欧拉定理 素数筛 快速幂取模PROBLEM
HDU – 1395
ANALYSIS
给出,找出最小的使其满足
假若 与 互质,那么 可被 n 整除。亦即
这个等式在和互质的时候一定成立
在这个题目中,因为
所以与不互质,除非为偶数,当然的时候需要特殊处理下,这些都是小问题,即在为奇数(大于1)的时候一定有解。
暴力的代码太zz了。
如果当为一个非常大的质数,那么暴力就会很慢。因为质数的欧拉函数就是质数-1。
更为高效的方法是:进行质因数分解。
然后依次枚举的每一个因子,同时判断这个因子是否满足,不断更新一个最小值,最后得到答案。
证明:
满足这个方程的最小称为对模的指数。我们记做,如果则我们称为模的原根
有:
根据以上所说:成立,那么也是成立的
所以就是的一个因子
Q.E.D.
SOLUTION
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int main() { int n; while (cin >> n) { if (n == 1 || n % 2 == 0) { printf("2^? mod %d = 1\n", n); continue; } int a = 2, sum = 1; while (a != 1) { a = (a << 1) % n; sum++; } printf("2^%d mod %d = 1\n", sum, n); } return 0; }
#include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; #define int long long const int N = 1000000; int v[N], s[N]; int vcnt, scnt; int phi[N]; bool check[N]; void gen(int n, int primelist[], bool check[], int phi[]) { memset(check, 0, sizeof(bool) * n); for (int i = 2, u; i < n; i++) { if (!check[i]) { primelist[vcnt++] = i; phi[i] = i - 1; } for (int j = 0; j < vcnt && i * primelist[j] < n; j++) { u = i * primelist[j]; check[u] = 1; if (i % primelist[j] == 0) { phi[u] = phi[i] * primelist[j]; break; } else { phi[u] = phi[i] * (primelist[j] - 1); } } } } int eular(int n) { int i, res = 1; for (i = 2; i * i <= n; i++) { if (n % i == 0) { res = res * (i - 1); n = n / i; while (n % i == 0) { res = res * i; n = n / i; } } if (n == 1) { break; } } if (n > 1) { res = res * (n - 1); } return res; } int fp(int a, int n, int m) { int ans = 1, t = a; while (n) { if (n & 1) { ans = ans * t % m; } t = t * t % m; n >>= 1; } return ans; } void exec(int n) { if (n < 3 || n % 2 == 0) { printf("2^? mod %lld = 1\n", n); return; } int ans, u, f; ans = u = f = eular(n); int t; bool flag = 0; do { flag = 0; scnt = 0; f = u; for (int i = 0; v[i]*v[i] <= f; i++) { while (f % v[i] == 0) { s[scnt++] = v[i]; f /= v[i]; } if (f == 1) { break; } } if (f > 1) { s[scnt++] = f; } for (int i = 0; i < scnt; i++) { t = s[i]; if (fp(2, u / t, n) == 1) { if (u / t < ans) { ans = u / t; } flag = 1; } } u = ans; } while (flag); printf("2^%lld mod %lld = 1\n", ans, n); } #undef int int main() { #define int long long gen(N, v, check, phi); for (int i; ~scanf("%lld", &i); exec(i)); return 0; }
P3 Dertouzos
费马小定理 素数筛PROBLEM
HDU – 5750
ANALYSIS
找的个数,使得且是的最大因子,设的最小素因子为,简单推导知只能取中的素数,而至多是级别,所以只需要预处理出中所有的素数即可。
可能是我写得不好吧,最后优化了输入输出才过了的。
调了一天bug了,心态有点爆炸,打个微笑脸。
SOLUTION
#include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; const int N = 60000; int p[N]; int cnt[N]; bool check[N]; int pcnt; void gi(int & a) { char t = getchar(); a = 0; for (; !isdigit(t); t = getchar()); for (; isdigit(t); a *= 10, a += t - 48, t = getchar()); } void gen(int n) { memset(check, 0, sizeof(bool) * n); pcnt = 0; for (int i = 2, u; i < n; i++) { cnt[i] = cnt[i - 1]; if (!check[i]) { p[pcnt++] = i; cnt[i]++; } for (int j = 0; j < pcnt && i * p[j] < n; j++) { u = i * p[j]; check[u] = 1; if (i % p[j] == 0) { break; } } } } int exec(int n, int d) { if ((n - 1) / 2 < d) { return 0; } int l = 0, r, c, m = d; for (int i = 0; i < pcnt && p[i]*p[i] <= d; ++i) { if (d % p[i] == 0) { m = p[i]; break; } } m = min((n - 1) / d, m); return cnt[m]; } int main() { gen(N); int T, a, b; cin >> T; while (T--) { gi(a), gi(b); printf("%d\n", exec(a, b)); } return 0; }
P4 Saving Beans
费马小定理 组合数取模 卢卡斯定理 快速幂PROBLEM
HDU – 3037
ANALYSIS
将不超过个果子分到个桶中的方案数(mod prime no greater than 1e5),有序,可空。
可用高中排列组合中隔板法解决。
另设一空桶,问题转化为将个果子分到个桶中,有序,不可空。
易得出
问题转化为求
可用卢卡斯定理得出。
卢卡斯定理:
对于非负整数m和n和素数p, 同余式:
成立。其中:
并且
是m和n的p进制展开。当m < n时,二项式系数。
SOLUTION
#include <iostream> #include <stdio.h> #include <algorithm> #include<cstring> using namespace std; typedef long long ll; ll quick_mod(ll a, ll b, ll m) { ll ans = 1; while (b) { if (b & 1) { ans = ans * a % m; } a = a * a % m; b >>= 1; } return ans; } ll comp(ll a, ll b, ll m) { if (a < b) { return 0; } if (a == b) { return 1; } if (b > a - b) { b = a - b; } ll ans = 1, ca = 1, cb = 1; for (int i = 0; i < b; i++) { ca = ca * (a - i) % m; cb = cb * (b - i) % m; } ans = ca * quick_mod(cb, m - 2, m) % m; return ans; } ll lucas(ll a, ll b, ll m) { ll ans = 1; while (a && b) { ans = (ans * comp(a % m, b % m, m)) % m; a /= m; b /= m; } return ans; } int main() { ll t, a, b, m; cin >> t; while (t--) { cin >> a >> b >> m; cout << lucas(a + b, b, m) << endl; } return 0; }
SUMMARY
emmm
REFERENCE
垃圾CSDN
- https://blog.csdn.net/a27038/article/details/77129556
- https://blog.csdn.net/xieshimao/article/details/6688618
- https://blog.csdn.net/xh_reventon/article/details/8690691
- https://blog.csdn.net/V5ZSQ/article/details/52021261
本作品使用基于以下许可授权:Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.