题意定义f(l,r)为去掉[l,r]部分后剩下的数任意两个数的最大公约数的最大值
现在求f(l,r)的和
由于每个数ai最大只有200000,因此我们穷举因子x,记录以其为因子的a[i]的i值并按i升序。
下面我们从大到小穷举每个因子x,我们依次计算以f(l,r)=x的区间数,
有了上述的维护信息,我们很容易三种情况的区间满足f(l,r)=x(我就不具体细说了)
令pre[i]表示当前以第i个位置结尾的区间满足任意j(1<=j<=pre[i]),f(j,i)<x
显然f(l,r)=x的区间数=当前还没计算过的区间数-∑pre[i]
这就要维护∑pre[i],每次修改是将一段区间pre[i]>x的数赋值为x
显然pre[i]是单调不上升,因此可以用线段树维护之
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 int laz[200010*4],mi[200010*4],mx[200010*4]; 6 ll tr[200010*4]; 7 vector<int> g[200010]; 8 int n,m; 9 void build(int i,int l,int r) 10 { 11 laz[i]=-1; 12 if (l==r) mx[i]=mi[i]=tr[i]=l; 13 else { 14 int m=(l+r)>>1; 15 build(i*2,l,m); 16 build(i*2+1,m+1,r); 17 tr[i]=tr[i*2]+tr[i*2+1]; 18 mx[i]=max(mx[i*2],mx[i*2+1]); 19 mi[i]=min(mi[i*2],mi[i*2+1]); 20 } 21 } 22 23 void work(int i,int l,int r,int x,int y,int z) 24 { 25 // if (i==1) cout <<z<<endl; 26 if (x>y) return; 27 if (mx[i]<=z) return; 28 if (x<=l&&y>=r&&mi[i]>z) 29 { 30 mi[i]=mx[i]=laz[i]=z; 31 tr[i]=(ll)(r-l+1)*z; 32 } 33 else { 34 int m=(l+r)>>1; 35 if (laz[i]>-1) 36 { 37 laz[i*2]=laz[i*2+1]=laz[i]; 38 mi[i*2]=mx[i*2]=laz[i]; 39 mi[i*2+1]=mx[i*2+1]=laz[i]; 40 tr[i*2]=(ll)laz[i]*(m-l+1); 41 tr[i*2+1]=(ll)laz[i]*(r-m); 42 laz[i]=-1; 43 } 44 if (x<=m) work(i*2,l,m,x,y,z); 45 if (y>m) work(i*2+1,m+1,r,x,y,z); 46 tr[i]=tr[i*2]+tr[i*2+1]; 47 mx[i]=max(mx[i*2],mx[i*2+1]); 48 mi[i]=min(mi[i*2],mi[i*2+1]); 49 } 50 } 51 52 int main() 53 { 54 scanf("%d",&n); 55 for (int i=1; i<=n; i++) 56 { 57 int x;scanf("%d",&x); 58 for (int j=1; j*j<=x; j++) 59 if (x%j==0) 60 { 61 g[x/j].push_back(i); 62 if (j*j!=x) g[j].push_back(i); 63 } 64 m=max(m,x); 65 } 66 build(1,1,n); 67 ll pre=(ll)n*(n+1)/2; 68 ll ans=0; 69 for (int i=m; i; i--) 70 { 71 if (g[i].size()<2) continue; 72 int j=g[i].size()-1; 73 work(1,1,n,g[i][0]+1,g[i][j]-1,g[i][0]); 74 work(1,1,n,1,g[i][j-1]-1,0); 75 work(1,1,n,g[i][1]+1,n,g[i][1]); 76 ans+=(pre-tr[1])*(ll)i; 77 // cout <<tr[1]<<endl; 78 pre=tr[1]; 79 } 80 printf("%lld\n",ans); 81 }