codeforces contest671的C题。
#include<bits/stdc++.h>//对函数f(i,j):left。right表示的是i的取值范围。此时j的取值为1-k,其中k>=minn[n]&&k<=maxn[n],且k(minn)=minn[n],k(maxn)=maxn[n] typedef long long ll; using namespace std; ll tree[200010<<2]; int minn[200010<<2]; int maxn[200010<<2]; int add[200010<<2]; void pushDown(int temp,int left,int mid,int right,int temps) { tree[temp<<1]=1LL*temps*(mid-left+1); tree[temp<<1|1]=1LL*temps*(right-mid); add[temp<<1]=temps; add[temp<<1|1]=temps; maxn[temp<<1]=maxn[temp<<1|1]=minn[temp<<1]=minn[temp<<1|1]=temps; add[temp]=0; } void ad(int i,int j,int temp,int left,int right,int n) { if(temp<=minn[n]) return; if(left>=i&&right<=j&&temp>=maxn[n]) { tree[n]=1LL*(right-left+1)*temp; add[n]=maxn[n]=minn[n]=temp; return; } int mid=(left+right)/2; if(add[n]) pushDown(n,left,mid,right,add[n]); if(j<=mid) ad(i,j,temp,left,mid,n<<1); else if(i>mid) ad(i,j,temp,mid+1,right,n<<1|1); else { ad(i,mid,temp,left,mid,n<<1); ad(mid+1,j,temp,mid+1,right,n<<1|1); } tree[n]=tree[n<<1]+tree[n<<1|1]; maxn[n]=max(maxn[n<<1],maxn[n<<1|1]); minn[n]=min(minn[n<<1],minn[n<<1|1]); } vector<int>v; int l[200010][2],r[200010][2]; ll ans[200010]; void deel(int pos,int val) { if(l[val][0]>pos||l[val][0]==0) { l[val][1]=l[val][0]; l[val][0]=pos; } else if(l[val][1]>pos||l[val][1]==0) l[val][1]=pos; if(r[val][0]<pos) { r[val][1]=r[val][0]; r[val][0]=pos; } else if(r[val][1]<pos) r[val][1]=pos; } int main() { int n; cin>>n; int val; for(int i=1; i<=n; i++) { scanf("%d",&val); for(int j=1; j*j<=val; j++) { if(val%j==0) { deel(i,j); if(j*j!=val) deel(i,val/j); } } } for(int i=1; i<=n; i++) ad(i,i,i-1,1,n,1); for(int i=200001; i>0; i--) { if(l[i][0]!=r[i][0]) { ad(1,l[i][0],r[i][1]-1,1,n,1);//当i在1-l[i][0]之间是,j必须小于等于r[i][1]-1才能保证把所有结果等于i的区间都包含进去了 ad(l[i][0]+1,l[i][1],r[i][0]-1,1,n,1);//同理 if(l[i][1]!=n) ad(l[i][1]+1,n,n,1,n,1);//同理,此时有可能l[i][1]==n } //此时线段树中存储的是使结果大于等于i的区间数目 ans[i]=1LL*n*n-tree[1];//所以ans[i]存储的是结果小于i的区间数目 } ll fin=0; for(int i=1;i<=200000;i++) fin+=(ans[i+1]-ans[i])*i; printf("%I64d ",fin); return 0; }