题意
定义 F(l,r) 的值表示序列 A[1:n] 的子序列 A[1...(l−1),(r+1)...n] 之中任意两个数的最大公约数的最大值。
题解
If we calculate an array H where Hi is how many (l - r)s there are that f(l, r) ≤ i, then we can easily calculate the answer.
How to calculate array H. Let’s keep a vector, vi keeps all elements indexes which contain i as a divisor — in sorted order. We will iterate over max element to 1. When we are iterating we will keep another array next, Let’s suppose we are iterating over i, nextj will keep leftmost k where f(j, k) ≤ i. Sometimes there is no such k, then nextj will be n + 1. Hi will be equal to , because if we choose p as l, r must be at least nextp, so for l we can choose n−nextp+1 different r s.
Let’s look how we update next array when we iterate i to i - 1.
Let vi be b1, b2, b3...bk . Note that our l - r must be cover at least k - 1 of this indexes. l must less or equal to b2 . So we have to maximize all nextp with n + 1 where p > b2 . Otherwise If l ≥ b1 + 1 then r must be at least bk, that’s we will maximize all next′ps where b1 < p ≤ b2 with bk. And finally for all nextp’s where (1 ≤ p ≤ b1) we have to maximize them with bk − 1 . Observe that next array will be monotonic - in non decreasing order - after all operations. So we can easily make our updates with a segment tree that can perform following operations:
- Returns rightmost index i where nexti is less than some k.
- Returns sum of all elements in next array.
- Can assign some k to all elements between some l and r.
If all update and queries performed in O(logn) then overall complexity will be O(nlogn), we can also apply all this operations with STL set in same complexity.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <bitset>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define ll long long
#define SZ(x) ((int)(x).size())
#define ALL(v) (v).begin(), (v).end()
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)
#define reveach(i, v) for (__typeof((v).rbegin()) i = (v).rbegin(); i != (v).rend(); ++ i)
#define REP(i,a,n) for ( int i=a; i<int(n); i++ )
#define FOR(i,a,n) for ( int i=n-1; i>= int(a);i-- )
#define lson rt<<1, L, m
#define rson rt<<1|1, m, R
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define mp(x, y) make_pair(x, y)
#define pb(x) push_back(x)
#define fi first
#define se second
#define CLR(a, b) memset(a, b, sizeof(a))
#define Max(a, b) a = max(a, b)
#define Min(a, b) a = min(a, b)
const int maxn = 2e5 + 7;
ll n;
ll a[maxn];
vector<ll> v[maxn];
ll sum[maxn << 2], mx[maxn << 2], mi[maxn << 2], lazy[maxn << 2];
ll H[maxn], inx[maxn];
ll L1[maxn], L2[maxn], R1[maxn], R2[maxn];
void pushUp(int rt){
int lch = rt << 1, rch = rt << 1 | 1;
mx[rt] = max(mx[lch], mx[rch]);
mi[rt] = min(mi[lch], mi[rch]);
sum[rt] = sum[lch] + sum[rch];
}
void pushDown(int rt, int L, int R){
int lch = rt << 1, rch = rt << 1 | 1;
int m = (L + R) >> 1;
if(lazy[rt]){
lazy[lch] = mx[lch] = mi[lch] = lazy[rt];
lazy[rch] = mx[rch] = mi[rch] = lazy[rt];
sum[lch] = lazy[rt] * (m - L);
sum[rch] = lazy[rt] * (R - m);
lazy[rt] = 0;
}
}
void build(int rt, int L, int R){
lazy[rt] = 0;
if(L + 1 == R){
mx[rt] = mi[rt] = sum[rt] = L;
return ;
}
int m = (L + R) >> 1;
build(lson);
build(rson);
pushUp(rt);
}
void update(int rt, int L, int R, int l, int r, ll val){
if(l >= r) return ;
if(mi[rt] >= val) return ;
if(l <= L && R <= r && mx[rt] <= val){
lazy[rt] = val;
mi[rt] = mx[rt] = val;
sum[rt] = (R - L) * val;
return ;
}
pushDown(rt, L, R);
int m = (L + R) >> 1;
if(l < m) update(lson, l, r, val);
if(r > m) update(rson, l, r, val);
pushUp(rt);
}
int main(){
#ifdef ac
freopen("in.txt","r",stdin);
#endif
//freopen("out.txt","w",stdout);
scanf("%lld", &n);
REP(i, 0, n) scanf("%lld", &a[i]);
CLR(inx, -1);
CLR(L1, -1);
CLR(L2, -1);
CLR(R1, -1);
CLR(R2, -1);
REP(i, 0, n) inx[a[i]] = i;
///预处理三个区间
REP(i, 1, maxn){
for(int j = i; j < maxn; j += i){
if(inx[j] != -1){
if(L1[i] == -1 || L1[i] > inx[j]) L2[i] = L1[i], L1[i] = inx[j];
else if(L2[i] == -1 || L2[i] > inx[j]) L2[i] = inx[j];
if(R1[i] < inx[j]) R2[i] = R1[i], R1[i] = inx[j];
else if(R2[i] < inx[j]) R2[i] = inx[j];
}
}
}
build(1, 0, n);
FOR(i, 1, maxn){
if(L1[i] != R1[i]){
update(1, 0, n, 0, L1[i] + 1, R2[i]);
update(1, 0, n, L1[i] + 1, L2[i] + 1, R1[i]);
update(1, 0, n, L2[i] + 1, n, n);
}
H[i] = n * n - sum[1];
}
ll ans = 0;
REP(i, 1, maxn - 1) ans += i * (H[i + 1] - H[i]);
printf("%lld\n", ans);
return 0;
}