题目:
https://ac.nowcoder.com/acm/contest/7817/B
给你
n
n
n个数,设
G
(
i
,
j
)
=
g
c
d
(
a
i
,
a
i
+
1
.
.
.
a
j
)
G(i,j)=gcd(a_i,a_{i+1}...a_j)
G(i,j)=gcd(ai,ai+1...aj),
M
(
i
,
j
)
=
m
a
x
(
a
i
,
a
i
+
1
.
.
.
a
j
)
M(i,j)=max(a_i,a_{i+1}...a_j)
M(i,j)=max(ai,ai+1...aj),计算
∑
1
≤
i
≤
j
≤
n
G
(
i
,
j
)
⋅
M
(
i
,
j
)
\sum_{1\le i\le j\le n}G(i,j)\cdot M(i,j)
1≤i≤j≤n∑G(i,j)⋅M(i,j)
思路:
这里要解决两个问题,一个是区间
g
c
d
gcd
gcd,一个是区间最大值求和。
- 首先对于 g c d gcd gcd来说,可以 n l o g m nlog^m nlogm,预处理出来, m m m是 a i a_i ai的最大值。假设右端点确定,则左端点越往左 g c d gcd gcd非严格递减,如果减少每次至少除 2 2 2,所以 g c d gcd gcd的个数是 l o g log log级别。所以区间然后可以通过 d p dp dp预处理出来每种 g c d gcd gcd最左边端点。
- 区间
g
c
d
gcd
gcd预处理出来后,枚举右端点
i
i
i,再枚举每种
g
c
d
gcd
gcd的最左端端点
j
j
j,假设上一次左端点为
k
k
k,我们要计算的是
∑ l = j k − 1 G ( l , i ) ⋅ M ( l , i ) \sum_{l=j}^{k-1}G(l,i)\cdot M(l,i) l=j∑k−1G(l,i)⋅M(l,i)
G ( l , i ) G(l,i) G(l,i)都是一样的,现在就是要计算最大值的和,可以预处理出一个前缀和,这前缀和是以 i i i为右端点往左边的最长递增序列,而每一个位置上的贡献就是这个位置上的值乘上和左边第一个比他大的值的距离。然后瞎搞计算。
#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
using namespace std;
const int N=200009;
struct node {
int l;
ll val;
node(int x,ll y):l(x),val(y) {}
};
int n,dp[N];
ll a[N],sum[N],ans=0;
vector<node>w[N];
namespace ST {
int a[N],n,dp[N][25],index[N][25],mm[N];//mm:logn/log2
void ST() {
mm[0]=-1;
for(int i=1; i<=n; ++i) {
dp[i][0]=a[i];
index[i][0]=i;
mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
}
for(int j=1; j<=mm[n]; ++j)
for(int i=1; (i+(1<<j)-1)<=n; ++i) {
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
if(dp[i][j-1]<=dp[i+(1<<(j-1))][j-1]) {
index[i][j]=index[i+(1<<(j-1))][j-1];
} else {
index[i][j]=index[i][j-1];
}
}
}
int query(int x,int y) {
int t=mm[y-x+1];
//return max(dp[x][t],dp[y-(1<<t)+1][t]);
if(dp[x][t]<=dp[y-(1<<t)+1][t])
return index[y-(1<<t)+1][t];
else return index[x][t];
}
}
int main() {
scanf("%d",&n);
ST::n=n;
for(int i=1; i<=n; i++)
scanf("%lld",&a[i]),ST::a[i]=a[i];
ST::ST();
a[0]=mod;
for(int i=1; i<=n; i++) {
int tmp=i-1;
while(a[tmp]<=a[i])
tmp=dp[tmp];
dp[i]=tmp;
}
sum[0]=0;
for(int i=1; i<=n; i++)
sum[i]=(sum[dp[i]]+(i-dp[i])*a[i]%mod)%mod;
for(int i=1; i<=n; i++) {
int si1=1;
w[i].push_back(node(i,a[i]));
int si=w[i-1].size();
for(int j=0; j<si; j++) {
ll tmp=__gcd(a[i],w[i-1][j].val);
if(tmp==w[i][si1-1].val)
w[i][si1-1].l=w[i-1][j].l;
else
w[i].push_back(node(w[i-1][j].l,tmp)),si1++;
}
}
/*for(int i=1; i<=n; i++)
for(int j=0; j<w[i].size(); j++)
printf("%d %d %lld\n",i,w[i][j].l,w[i][j].val);*/
for(int i=1; i<=n; i++) {
int si=w[i].size();
ll tmp=0;
for(int j=0; j<si; j++) {
int locate=ST::query(w[i][j].l,i);
ll ans1;
ll Sum=(sum[i]-sum[locate]+mod+a[locate]*(locate-w[i][j].l+1)%mod)%mod;
ans1=(Sum*w[i][j].val%mod-tmp*w[i][j].val%mod+mod)%mod;
ans=(ans+ans1)%mod;
tmp=Sum;
//printf("%d %d %d %lld %lld\n",i,w[i][j].l,locate,w[i][j].val,ans1);
}
}
printf("%lld",ans);
return 0;
}