歐拉篩
阿新 • • 發佈:2018-07-27
http 嘗試 質因數分解 span void can == n) str 。總的復雜度應該是預處理和求解:\(O(m+n log m)\),m表示\(a_i\)的上限\(10^6\)。因為質因數分解需要log的復雜度,每次除去最小質因子,直到\(1\)。
歐拉篩可以\(O(n)\)篩素數,其本質是拿每個合數的最小質因子把這個合數篩掉。
void prime(int m) { memset(flag, 1, sizeof flag); cnt = 0; for(int i=2; i<=m; i++) { if(flag[i]) pr[++ cnt] = i; for(int j=1; j<=cnt && i * pr[j] <= m; j++) { flag[i * pr[j]] = 0; if(i % pr[j] == 0) break ; } } }
例題1
題意
給定一個長度為\(n\)(\(n\)<=\(10^5\))的序列\(a\) (\(a_i <= 10^6\)),求最長的滿足\(\prod_{i=l}^{r} a_i = lcm(a_l, a_{l+1}, \ldots, a_{r-1}, a_r)\)的子段長度.
題解
歐拉篩線性篩出每個數的最小質因子,\(x\)的最小質因子在\(pr\)中的下標記為\(f(x)\),即\(x\)的最小質因子為\(pr_f(x)\)。
然後從\(1\)到\(n\)開始,記錄右端點\(r\),嘗試把\(a_r\)質因數分解加進去,直到加不進去,更新答案,把左端點向右移動一位。由於左右端點始終單調遞增,復雜度\(O(n)\)
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int MAXN = 100010; const int MAXA = 1000010; int n, a[MAXN], f[MAXA]; bool flag[MAXA]; int pr[MAXA], k[MAXA], cnt; void prime(int m) { memset(flag, 1, sizeof flag); cnt = 0; for(int i=2; i<=m; i++) { if(flag[i]) pr[++ cnt] = i, f[i] = cnt; for(int j=1; j<=cnt && i * pr[j] <= m; j++) { flag[i * pr[j]] = 0; f[i * pr[j]] = j; if(i % pr[j] == 0) break ; } } } bool valid(int x) { while(x > 1) { if(k[ f[x] ]) return false; x /= pr[f[x]]; } return true; } void add(int x, int v) { while(x > 1) { k[ f[x] ] += v; x /= pr[f[x]]; } } int main() { prime(1e6); int T; scanf("%d", &T); for(int Case = 1; Case <= T; ++ Case) { int ans = -1; scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%d", &a[i]); int r = 0; for(int i=1; i<=n; i++) { while(r < n && valid(a[r + 1])) add(a[++ r], 1); ans = max(ans, r - i + 1); add(a[i], -1); } if(ans < 2) ans = -1; printf("Case %d: %d\n", ans); } return 0; }
例題2:[51 Nod] 1643
題目傳送門
待填坑。
歐拉篩