题意是求所有区间[i,j],f(i,j)的和。f(i,j)表示除去i,j的区间之外的数其中两个最大的gcd。
ai是从1到200000的数,对于每一个i维护一个区间h(j,k),h(j,k)的含义是f(j,k)<=i,对于每一个j,找最小的k。
然后对于i来说的话,gcd<=i的区间数目就可以枚举j,对每一个j算相应的k值,也就是题解中的next[j]值。sum(n-next[j]+1) (1<=j<=n)
可以发现就是找能够整除这个数的最左距离,次左距离,次右距离,最右距离。
之后就是使用线段树更新这个和了。
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-9
#define maxn 200010
#define MOD 1000000007
typedef long long LL;
struct node
{
int l,r;
int Min,Max,lazy;
long long sum;
} tree[maxn*4];
int n,a[maxn],idx[maxn];
int l1[maxn],l2[maxn],r1[maxn],r2[maxn];
long long tmp[maxn];
void pushup(int pos)
{
tree[pos].Max = max(tree[pos<<1].Max,tree[pos<<1|1].Max);
tree[pos].Min = min(tree[pos<<1].Min,tree[pos<<1|1].Min);
tree[pos].sum = tree[pos<<1].sum + tree[pos<<1|1].sum;
}
void pushdown(int pos)
{
if(!tree[pos].lazy)
return;
tree[pos<<1].Max = tree[pos<<1|1].Max = tree[pos].lazy;
tree[pos<<1].Min = tree[pos<<1|1].Min = tree[pos].lazy;
tree[pos<<1].lazy = tree[pos<<1|1].lazy = tree[pos].lazy;
tree[pos<<1].sum = (long long)(tree[pos<<1].r - tree[pos<<1].l+1) * tree[pos].lazy;
tree[pos<<1|1].sum = (long long)(tree[pos<<1|1].r-tree[pos<<1|1].l+1) * tree[pos].lazy;
tree[pos].lazy = 0;
}
void build(int l,int r,int pos)
{
tree[pos].l = l;
tree[pos].r = r;
tree[pos].lazy = 0;
if(l == r)
{
tree[pos].Max = tree[pos].Min = l;
tree[pos].sum = (long long)l;
return;
}
int mid = (l+r)/2;
build(l,mid,pos<<1);
build(mid+1,r,pos<<1|1);
pushup(pos);
} //建树 //查询操作
void update(int l,int r,int pos,int val)
{
if(l > r)
return ;
if(tree[pos].Min >= val) //这里需要注意单独写
return;
if(tree[pos].l == l && tree[pos].r == r && tree[pos].Max <= val) //<span style="font-family:SimSun;">这里需要写在判断上,不能写在里面</span>
{
tree[pos].sum = (long long)(r-l+1) * val;
tree[pos].Max = tree[pos].Min = val;
tree[pos].lazy = val;
return ;
}
pushdown(pos);
int mid = (tree[pos].l + tree[pos].r) >> 1;
if(r <= mid)
update(l,r,pos<<1,val);
else if(l > mid)
update(l,r,pos<<1|1,val);
else
{
update(l,mid,pos<<1,val);
update(mid+1,r,pos<<1|1,val);
}
pushup(pos);
} //自上而下更新节点
int main()
{
int t;
while(scanf("%d",&n) != EOF)
{
memset(l1,0,sizeof(l1));
memset(l2,0,sizeof(l2));
memset(r1,0,sizeof(r1));
memset(r2,0,sizeof(r2));
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
idx[a[i]] = i;
}
for(int i = 1; i <= maxn; i++)
for(int j = i; j <= maxn; j+=i)
if(idx[j])
{
if(!l1[i] || l1[i] > idx[j])
{
l2[i] = l1[i];
l1[i] = idx[j];
}
else if(!l2[i] || l2[i] > idx[j])
l2[i] = idx[j];
if(!r1[i] || r1[i] < idx[j])
{
r2[i] = r1[i];
r1[i] = idx[j];
}
else if(!r2[i] || r2[i] < idx[j])
r2[i] = idx[j];
}
build(1,n,1);
for(int i = maxn; i > 0; i--)
{
if(l1[i] != r1[i])
{
update(1,l1[i],1,r2[i]);
update(l1[i]+1,l2[i],1,r1[i]);
update(l2[i]+1,n,1,n+1);
}
tmp[i] = n*(n+1) - tree[1].sum;
}
long long ans = 0;
for(int i = 1; i < maxn; i++)
ans += (long long)i * (tmp[i+1] - tmp[i]);
printf("%lld\n",ans);
}
return 0;
}