大意: 定义一个数列的特征值为两个数gcd的最大值, $f(l,r)$表示数列删除区间$[l,r]$的元素后剩余元素的特征值, 求$\sum_{i=1}^n\sum_{j=i}^n{f(i,j)}$
这题感觉好难啊, 特征值没看出来要怎么处理, 直接看题解了
#include <iostream> #include <algorithm> #include <cstdio> #define PER(i,a,n) for(int i=n;i>=a;--i) #define REP(i,a,n) for(int i=a;i<=n;++i) #define mid ((l+r)>>1) #define lc (o<<1) #define rc (lc|1) #define ls lc,l,mid #define rs rc,mid+1,r using namespace std; typedef long long ll; const int N = 1e6+10, INF = 0x3f3f3f3f; int n, mx, a[N]; struct { int ma,mi,tag; ll sum; void upd(int x, int t) { ma=mi=tag=x, sum=(ll)t*x; } } tr[N<<2]; int L1[N], L2[N], R1[N], R2[N]; ll H[N]; void pu(int o) { tr[o].ma = max(tr[lc].ma,tr[rc].ma); tr[o].mi = min(tr[lc].mi,tr[rc].mi); tr[o].sum = tr[lc].sum+tr[rc].sum; } void pd(int o, int l, int r) { if (tr[o].tag) { tr[lc].upd(tr[o].tag,mid-l+1); tr[rc].upd(tr[o].tag,r-mid); tr[o].tag = 0; } } void build(int o, int l, int r) { if (l==r) return tr[o].upd(l,1); build(ls),build(rs); pu(o); } void update(int o, int l, int r, int ql, int qr, int v) { if (ql>qr||tr[o].mi>=v) return; if (ql<=l&&r<=qr&&tr[o].ma<=v) return tr[o].upd(v,r-l+1); pd(o,l,r); if (mid>=ql) update(ls,ql,qr,v); if (mid<qr) update(rs,ql,qr,v); pu(o); } int main() { scanf("%d", &n); REP(i,1,n) { int t; scanf("%d", &t); a[t] = i; mx = max(mx, t); } REP(i,1,mx) { for (int j=i; j<=mx; j+=i) if (a[j]) { if (!L1[i]||L1[i]>a[j]) L2[i] = L1[i], L1[i] = a[j]; else if (!L2[i]||L2[i]>a[j]) L2[i] = a[j]; if (R1[i]<a[j]) R2[i] = R1[i], R1[i] = a[j]; else if (R2[i]<a[j]) R2[i] = a[j]; } } build(1,1,n); PER(i,1,mx) { if (L1[i]!=R1[i]) { update(1,1,n,1,L1[i],R2[i]); update(1,1,n,L1[i]+1,L2[i],R1[i]); update(1,1,n,L2[i]+1,n,n+1); } H[i] = (ll)(n*(n+1))-tr[1].sum; } ll ans = 0; REP(i,1,mx-1) { ans += (ll)i*(H[i+1]-H[i]); } printf("%lld\n", ans); }