boolcheck(int n){ if (n < 2) returnfalse; int s = sqrt(n); for (int i = 2; i < n; i++) { if (n % i == 0) returnfalse; } returntrue; }
时间复杂度:除了第一个都是 O(n),还是比较可观的。
分解质因数
这里要用到一个结论,即对任意整数 n 中比 n 大的质因数最多只有一个,可以用反证法证明。
因此,可以这样分解:
1 2 3 4 5 6 7 8 9 10 11 12
voidfactorize(int n){ for (int i = 2; i <= n / i; i++) { int cnt = 0; while (n % i == 0) { n /= i; cnt++; } if (cnt) cout << i << ' ' << cnt << '\n'; } if (n != 1) cout << n << " 1\n"; }
intmain(){ cin.tie(0), cout.tie(0), ios::sync_with_stdio(false); unordered_map<int, int> primes; int n; cin >> n; while (n--) { int a; cin >> a; for (int i = 2; i <= a/i; i++) { while (a % i == 0) { a /= i; // operator[] 不存在时会新建 primes[i]++; } } // 注意,a 还可能有一个比它开方大的因数 并且这一步是放到 for 循环下面的 // 因为这是 a 在试完所有比 a 开方小的数之后留下的质因数 if (a > 1) primes[a]++; } longlong ans = 1; for (auto prime : primes) ans = (ans*(prime.second+1)) % N; cout << ans << '\n'; return0; }
关于 primes[i]++ 这一步,可以找到 operator[] 的解释:
Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.
#include<iostream> #include<unordered_map> usingnamespace std; constint N = 1e9+7;
intmain(){ unordered_map<int, int> primes; int n; cin >> n; while (n--) { int a; cin >> a; for (int i = 2; i <= a/i; i++) { while (a % i == 0) { a /= i; primes[i]++; } } if (a > 1) primes[a]++; } longlong ans = 1; for (auto prime : primes) { int p = prime.first, a = prime.second; longlong t = 1; // t = p^0+p^1+...+p^a // 这一步在求哈希值的时候也用过 本质上相当于一个 p 进制数的每位都为1 // 一共有 a+1 位, 这里如果循环一次那么这个数字是 p 进制的 11 // 所以循环 a 次就够了 while (a--) t = (t*p+1) % N; ans = (ans * t) % N; } cout << ans << '\n'; return0; }
对于后面的两个 % N 操作,我们可以把模的乘法分配律和模的加法分配律自由组合,而且由加法结合律也可以把多项式中的几项任意组合然后取模,结果也是不会改变的,所以 t = (t*p+1)%N 最后求得的就是这个等比数列前a+1 项和模 N,(ans * t) % N 最后也能算到一个正确的结果。
最大公约数
辗转相除法:
gcd(a,b)=gcd(b,a mod b)
这个证明起来也是比较容易的,设 d 是 a 和 b 的任意一个公约数,都有如下式子:
a mod ba⇒a−kb=a−⌊ba⌋b=a−kb=md,b=nd=md−knd=(m−kn)d
所以 a 和 b 与 b 和 a%b 的所有约数都相等,那么最大公约数自然也相等。
1 2 3
intgcd(int a, int b){ return b ? gcd(b, a%b) : a; }
voidfactorize(int t){ for (int i = 2; i <= t/i && t != 1; i++) { while (t % i == 0) { ans[i]++; t /= i; } } if (t != 1) ans[t]++; }
intmain(){ scanf("%d", &n); for (int i = 2; i <= n; i++) factorize(i); for (int i = 2; i <= n/i; i++) { if (ans[i]) printf("%d %d\n", i, ans[i]); } return0; }
先筛出数据范围 1∼106 所有质数,然后对于每个质数 p,从 1∼n 中是 p 的倍数的数字的个数是 ⌊pn⌋,不断累加 p2,p3,⋯,pk 就可得到质因子的数量,因为 pk 需要被累加 k 次。
cnt(p)=i=1∑pi≤n⌊pin⌋
在 N 个数中筛出所有质数,然后对每个质数进行对数级别的操作,结合素数分布定理,在 N 个数中质数有 lnNN 个,那么最终的复杂度就是 O(N+lnNNlogN)=O(N)
typedeflonglong LL; int primes[9] = {2, 3, 5, 7, 11, 13, 17, 19, 23}; int n, maxd, number;
// 素数索引 上一个次数 乘积 约数个数 voiddfs(int u, int last, int p, int d){ if (d > maxd || d == maxd && p < number) { maxd = d; number = p; } if (u == 9) return; for (int i = 1; i <= last; i++) { if ((LL)p * primes[u] > n) break; p *= primes[u]; dfs(u+1, i, p, d*(i+1)); } }
structFactor { int p, s; }; vector<Factor> factors; vector<int> primes;
bool st[N+1]; int a0, a1, b0, b1, ans;
voidinit(){ for (int i = 2; i <= N; i++) { if (!st[i]) primes.push_back(i); for (int j = 0; primes[j] <= N/i; j++) { st[primes[j] * i] = true; if (i % primes[j] == 0) break; } } }
voidfactorize(int t){ factors.clear(); for (int p : primes) { if (t == 1) break; int s = 0; while (t % p == 0) s++, t /= p; if (s) factors.push_back({p, s}); } if (t != 1) factors.push_back({t, 1}); }
intgcd(int a, int b){ return a ? gcd(b%a, a) : b; } intlcm(int a, int b){ return (longlong)a*b / gcd(a, b); }
voiddfs(int u, int p){ if (u >= factors.size()) { if (gcd(p, a0) == a1 && lcm(p, b0) == b1) ans++; return; } for (int s = 0; s <= factors[u].s; s++) { dfs(u+1, p); p *= factors[u].p; } }