題意:給一個n,然後n個數,求∑i=1n∑j=inf(i,j) mod (109+7).
也就是求n*(n+1)/2個區間內,給定一個i,使得i的左右兩邊的數都不能被a[i]
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int maxn = 100005;
int arr[maxn];
int l[maxn],r[maxn];
const int MOD = 1e9+7;
vector<int> v[10005];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=101;i<=10000;i++) v[i].clear(); //預處理l和r以及把大於100的數的下標放入v容器
for(int i=1;i<=n;i++) {
scanf("%d",&arr[i]);
l[i]=0;
r[i]=n+1;
if(arr[i]>100) v[arr[i]].push_back(i);
}
for(int i=1;i<=100;i++) //更新[n個數中能被100以內的數整除的l]使得該a[l](0<a[l]<=100)成爲【位於a[j]左邊】【離a[j]最近的】能被a[j]整除的一百以內的數
{
int maxl=0;
for(int j=1;j<=n;j++)
{
if(arr[j]%i==0) l[j]=max(maxl,l[j]);
if(arr[j]==i) maxl=j;
}
}
for(int i=1;i<=100;i++) //更新[n個數中能被100以內的數整除的r]使得該a[r](0<a[r]<=100)成爲【位於a[j]右邊】【離a[j]最近的】能被a[j]整除的一百以內的數
{
int minr=n+1;
for(int j=n;j>=1;j--)
{
if(arr[j]%i==0) r[j]=min(minr,r[j]);
if(arr[j]==i) minr=j;
}
}
for(int j=1;j<=n;j++) //對於從左往右依次出現的a[j]依次更新是a[j]倍數的數的l
{
if(arr[j]>100)
for(int i=arr[j];i<=10000;i+=arr[j])
{
for(int k=v[i].size()-1;k>=0;k--)
{
if(v[i][k]<=j) break;
else l[v[i][k]]=max(j,l[v[i][k]]);
}
}
}
for(int j=1;j<=n;j++) //對於從左往右依次出現的a[j]依次更新是a[j]倍數的數的r
{
if(arr[j]>100)
for(int i=arr[j];i<=10000;i+=arr[j])
{
for(int k=0;k<v[i].size();k++)
{
if(v[i][k]>=j) break;
else r[v[i][k]]=min(j,r[v[i][k]]);
}
}
}
long long sum=0;
for(int i=1;i<=n;i++)
{
sum=((sum+(i-l[i])*(r[i]-i))%(MOD));
}
printf("%I64d\n",sum);
}
}