題庫連接(最近 \(\text{bzoj}\) 維護上不去,就給洛谷的連接了...c++
給定長度爲 \(n\) 的正整數序列 \(A\)。定義一連續子段 \([l,r]\),其權值爲 \[\left(\gcd\limits_{l\leq i\leq r}^{}A_i\right) \times (r-l+1)\]spa
求子段最大權值爲多少。code
\(1\leq n\leq 100000,1\leq A_i\leq 10^{12}\)ip
顯然對於一個肯定的右端點,其左端點全部取值中,一整段的 \(\gcd\) 種數是不超過 \(\log A_i\) 的。get
咱們只需存下這 \(\log A_i\) 個公約數並記錄對應的最靠左的左端點便可。it
時間複雜度爲 \(O(n\log^2 A_i)\)。io
#include <bits/stdc++.h> #define ll long long #define pli pair<ll, int> #define fr first #define sc second #define pb push_back using namespace std; const int N = 100000+5; int n, cnt; ll a[N], ans; vector<pli > g[N]; ll gcd(ll a, ll b) {return b ? gcd(b, a%b) : a; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%lld", &a[i]); for (int i = 1; i <= n; i++) { cnt = 0; for (int j = 0, sz = g[i-1].size(); j < sz; j++) { pli x = g[i-1][j]; ll t = gcd(a[i], x.fr); ans = max(ans, t*(i-x.sc+1)); if (!cnt || t != g[i][cnt-1].fr) g[i].pb(pli(t, x.sc)); ++cnt; } pli x = pli(a[i], i); ll t = gcd(a[i], x.fr); ans = max(ans, t*(i-x.sc+1)); if (!cnt || t != g[i][cnt-1].fr) g[i].pb(pli(t, x.sc)); } printf("%lld\n", ans); return 0; }