题意:
解法:
对于M(i,j),肯定是想对于每个值,计算他能作为最大值的区间,
知道了M(i,j),G(i,j)怎么办?
因为区间gcd每增加一个数,一定是非递增的,因此对于固定的M,G一定是这样的:
即M的两边一定是一段一段的,而且是递减的,最多log段。
因为M是固定的,G的每一段是相同的,(每一段的长度可以用二分一个一个求出来),
那么选取左边的一段和右边的一段进行匹配,统计答案,
可以两层循环枚举,复杂度是O(log*log)的。
区间gcd的区间最值点可以用st表快速计算。
-----分割线-----
一开始计算求出整个序列的最大值位置m,计算出当前a[m]作为最大值的答案之后,
递归处理[1,m-1]和[m+1,r]。
ps:
如果存在相同的最大值,第一层是其中一个占用整个序列,
第二层是另外一个最大值切割后(递归的时候切割了)的某段序列,
这样好像能保证不重复计算。
code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxm=2e5+5;
const int mod=1e9+7;
int lg2[maxm];
int a[maxm];
int n;
struct ST{
int m[maxm][25];
int g[maxm][25];
static const int maxd=20;
void init(){
for(int i=1;i<=n;i++){
m[i][0]=i;
g[i][0]=a[i];
}
for(int j=1;j<=maxd;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
if(a[m[i][j-1]]>a[m[i+(1<<(j-1))][j-1]])m[i][j]=m[i][j-1];
else m[i][j]=m[i+(1<<(j-1))][j-1];
//
g[i][j]=__gcd(g[i][j-1],g[i+(1<<(j-1))][j-1]);
}
}
}
int m_ask(int l,int r){
int k=lg2[r-l+1];
int x=m[l][k],y=m[r-(1<<k)+1][k];
return a[x]>a[y]?x:y;
}
int g_ask(int l,int r){
int k=lg2[r-l+1];
return __gcd(g[l][k],g[r-(1<<k)+1][k]);
}
}T;
void lg2_init(){
lg2[1]=0;
for(int i=2;i<maxm;i++){
lg2[i]=lg2[i-1];
if((i&(i-1))==0)lg2[i]++;
}
}
int solve(int l,int r){
if(l>r)return 0;
int m=T.m_ask(l,r);
vector<int>L,R;
L.push_back(m+1);
R.push_back(m-1);
//right
int p=m;
while(p<=r){
int g=T.g_ask(m,p);
int lc=p,rc=r;
int pos=-1;
while(lc<=rc){
int mid=(lc+rc)/2;
if(T.g_ask(m,mid)==g){
pos=mid,lc=mid+1;
}else{
rc=mid-1;
}
}
R.push_back(pos);
p=pos+1;
}
//left
p=m;
while(p>=l){
int g=T.g_ask(p,m);
int lc=l,rc=p;
int pos=-1;
while(lc<=rc){
int mid=(lc+rc)/2;
if(T.g_ask(mid,m)==g){
pos=mid,rc=mid-1;
}else{
lc=mid+1;
}
}
L.push_back(pos);
p=pos-1;
}
//
int ans=0;
for(int i=1;i<(int)L.size();i++){
for(int j=1;j<(int)R.size();j++){
int gg=T.g_ask(L[i],R[j]);
int temp=1ll*(L[i-1]-L[i])*(R[j]-R[j-1])%mod;
ans=(ans+1ll*a[m]*gg%mod*temp%mod)%mod;
}
}
return (1ll*ans+solve(l,m-1)+solve(m+1,r))%mod;//int是2e9,这里三个加起来最大3e9,可能会爆,所以加ll
}
signed main(){
lg2_init();
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
T.init();
int ans=solve(1,n);
printf("%d\n",ans);
return 0;
}