题意:对于已知a数组,f(l,r)表示[l,r]中有几个i,存在[l,r]中除了i位置,其他位置都不是a[i]的因子,求总区间的所有子区间的f(l,r)的和
∑∑f(i,j) mod (109+7)
思路:首先预处理每一个位置左右最近的因子,然后对于每一个位置计算。所有包含当前位置的并i满足f(l,r)的区间的个数。然后对于每个位置左右的位置排列组合的和就是(i-l[i])*(r[i]-i);
因为左面可以取长度0,1,2,,,(i-l[i]-1),右面可以取的长度是0,1,,,(r[i]-i-1),左右两面随机组合就是积。
感想:这个题有点思维转折,由考虑区间,转为考虑每一个位置元素,比较偏思维性
代码:
#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
int n,l[100005],r[100005],a[100005],poit[100005];
long long ans;
int main()
{
while(~scanf("%d",&n))
{
memset(poit,0,sizeof(poit));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)
{
l[i]=0;
for(int j=1;j*j<=a[i];j++)
{
if(a[i]%j) continue;
if(poit[j]) l[i]=max(l[i],poit[j]);
if(poit[a[i]/j]) l[i]=max(l[i],poit[a[i]/j]);
}
poit[a[i]]=i;
}
memset(poit,0,sizeof(poit));
for(int i=n;i>=1;i--)
{
r[i]=n+1;
for(int j=1;j*j<=a[i];j++)
{
if(a[i]%j) continue;
if(poit[j]) r[i]=min(r[i],poit[j]);
if(poit[a[i]/j]) r[i]=min(r[i],poit[a[i]/j]);
}
poit[a[i]]=i;
}
ans=0;
for(int i=1;i<=n;i++)
{
ans+=((i-l[i])*(r[i]-i))%mod;
ans%=mod;
}
printf("%lld\n",ans);
}
}