CF671C Ultimate Weirdness of an Array
阿新 • • 發佈:2020-08-04
n<=200000個數(<=200000),問所有的f(i,j)的和,f(i,j)表示去掉區間i到j後的剩餘的數字中任選兩個數的最大gcd
首先我們用\(nxt_l\)表示當\(f(l,r)\le i\)時,\(l\)對應的右端點\(r\)最往左能取到哪裡,初始時\(nxt_l=l\),如果不存在合法右端點就記\(nxt_l=n+1\)。
然後考慮從大到小列舉\(i\),當從\(f(l,r)\le i\)變為\(f(l,r)\le i-1\)時,我們需要刪除\(gcd=i\)的貢獻,找出\(i\)的倍數在原序列中的下標記為\(x_1,x_2......x_m\),而我們新得到的區間\([l,nxt_l']\)
-
\(l\in(x_2,n]\),\(nxt_l=n+1\)
-
\(l\in(x_1,x_2]\),\(nxt_l=max(nxt_l,x_m)\)
-
\(l\in[1,x_1]\),\(nxt_l=max(nxt_l,x_{m-1})\)
2,3操作看似需要吉司機線段樹來維護,但是我們冷靜下來分析一波,\(nxt\)陣列一定是單調不降,所以一定是進行區間的一段字首覆蓋,直接線段樹上二分修改複雜度就是\(O(nlogn)\)。
其實開始時\(O(n\sqrt n)\)處理每個數倍數的位置就已經足夠了,但是也可以優化,因為我們最多隻需要2個開頭的和2個結尾的,那麼直接合並\(i\)
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #define zrt k << 1 #define yrt k << 1 | 1 const int N = 2e5; using namespace std; int n,a[N + 5],Mx; long long ans,las; vector <int> d[N + 5]; struct Seg { long long sm[N * 5 + 5],tag[N * 4 + 5]; int mi[N * 4 + 5],mx[N * 4 + 5]; void pushup(int k) { sm[k] = sm[zrt] + sm[yrt]; mi[k] = min(mi[zrt],mi[yrt]); mx[k] = max(mx[zrt],mx[yrt]); } void build(int k,int l,int r) { if (l == r) { mx[k] = mi[k] = sm[k] = l; return; } int mid = l + r >> 1; build(zrt,l,mid); build(yrt,mid + 1,r); pushup(k); } void cha(int k,int l,int r,int z) { sm[k] = 1ll * (r - l + 1) * z; mi[k] = mx[k] = z; tag[k] = z; } void pushdown(int k,int l,int r,int mid) { if (tag[k]) { cha(zrt,l,mid,tag[k]); cha(yrt,mid + 1,r,tag[k]); tag[k] = 0; } } void modify(int k,int l,int r,int x,int y,int z) { if (x > y) return; if (r < x || l > y || mi[k] >= z) return; if (l >= x && r <= y && mx[k] <= z) { cha(k,l,r,z); return; } if (l == r) { sm[k] = mi[k] = mx[k] = z; return; } int mid = l + r >> 1; pushdown(k,l,r,mid); modify(zrt,l,mid,x,y,z); modify(yrt,mid + 1,r,x,y,z); pushup(k); } }tree; int main() { scanf("%d",&n); for (int i = 1;i <= n;i++) scanf("%d",&a[i]),Mx = max(Mx,a[i]); for (int i = 1;i <= n;i++) for (int j = 1;j * j <= a[i];j++) if (a[i] % j == 0) { d[j].push_back(i); if (j * j != a[i]) d[a[i] / j].push_back(i); } tree.build(1,1,n); las = 1ll * n * (n + 1) - tree.sm[1]; int x1,x2,x3,x4; for (int i = Mx;i >= 1;i--) { if (d[i].size() < 2) continue; x1 = *d[i].begin(); x2 = *(d[i].begin() + 1); x3 = *(d[i].end() - 2); x4 = *(d[i].end() - 1); tree.modify(1,1,n,x2 + 1,n,n + 1); tree.modify(1,1,n,x1 + 1,x2,x4); tree.modify(1,1,n,1,x1,x3); ans += (las - (1ll * n * (n + 1) - tree.sm[1])) * i; las = 1ll * n * (n + 1) - tree.sm[1]; } cout<<ans<<endl; return 0; }