分析:题意是给你n个数字,全部区间[i,j](1<=i<=n,i<=j<=n)内满足一个数与区间中的其他数互质的数有多少个。定义两个一维数组l,r,l[i]和r[i]表示第i个数左侧和右侧最接近a[i]的且是a[i]的因子的数的位置,那么a[i]在区间(x,y)(l[i]<x<=i,i<=y<r[i])内均满足和区间内的其他元素互质,所以a[i]能贡献的答案是(i-l[i])*(r[i]-i)。
# include <stdio.h> # include <string.h> # define mod 1000000007 # define MAX(x,y) ((x)>(y))?(x):(y) # define MIN(x,y) ((x)<(y))?(x):(y) int a[100005],l[100005],r[100005],mark[100005]; int main() { int i,j,n,tmp; __int64 a1,a2,sum; while(scanf("%d",&n)!=EOF) { for(i=1;i<=n;i++) { l[i]=0; r[i]=n+1; scanf("%d",&a[i]); } memset(mark,0,sizeof(mark)); for(i=1;i<=n;i++)//a[1]~a[n]寻找a[i]的l[i]值, { for(j=1;j*j<=a[i];j++)//枚举a[i]的因子 { if(a[i]%j) continue; if(mark[j])//j为a[i]的因子,判断a[i]的左侧有没有j l[i]=MAX(l[i],mark[j]); if(mark[a[i]/j])//同样a[i]/j也为a[i]的因子 l[i]=MAX(l[i],mark[a[i]/j]); } mark[a[i]]=i;//每次查找完标记a[i]的位置 } memset(mark,0,sizeof(mark)); for(i=n;i>=1;i--)//查找r[i] { for(j=1;j*j<=a[i];j++) { if(a[i]%j) continue; if(mark[j]) r[i]=MIN(r[i],mark[j]); if(mark[a[i]/j]) r[i]=MIN(r[i],mark[a[i]/j]); } mark[a[i]]=i; } for(i=1,sum=0;i<=n;i++) { a1=i-l[i]; a2=r[i]-i; sum=(sum+a1*a2)%mod; } printf("%I64d\n",sum); } return 0; }