题意 :求解区间内不能整出其他数的个数.
转化思想:对数组a,求解有多少个满足a[i]不能整除区间其他数的区间个数.
解题:
需要知道满足a[i]的区间的最大范围,即左端点和右端点。建立L,R数组,L[i]表示包含a[i]的最大左端点,R[i]表示包含a[i]的最大右端点.L,R记录的是最靠近a[i]的因子的下标。
包含a[i]的区间个数为(i-L[i])*(R[i]-i);
sum+=(i-L[i])*(R[i]-i).
求L从左靠近i,求R从右靠近i.更新因子下标.
为避免每次都要查找因子是否存在在数组a中.用Index数组记录a[i]的下标,Index[a[i]]=i.初始Index=-1.
拿求左端点为例,j为a[i]因子.
/*if(Index[j]!=-1)L[i]=Max(Index[j],L[i]);*/ 因子j本身已经在数组a中,更新L /*if(Index[a[i]/j]!=-1)L[i]=Max(Index[a[i]/j],L[i]); */ 因子a[i]/j在数组a中,更新L.
/*Index[a[i]]=i*/ 记录a[i]下标AC代码:
#include<stdio.h> #include<math.h> #include<string.h> #include<stdlib.h> #define MAX 100010 #define Max(a,b) a>b?a:b #define Min(a,b) a<b?a:b int L[MAX],R[MAX],a[MAX],Index[MAX]; int n,mod=1e9+7; void read(){ int i; for(i=1;i<=n;i++){ scanf("%d",a+i); L[i]=0; R[i]=n+1; } return ; } int main(){ int i,j,temp,sum; while(scanf("%d",&n)!=EOF){ read(); sum=0; memset(Index,-1,sizeof(Index)); for(i=1;i<=n;i++){ temp=sqrt(1.0*a[i]); for(j=1;j<=temp;j++){ if(a[i]%j==0){ if(Index[j]!=-1)L[i]=Max(Index[j],L[i]); if(Index[a[i]/j]!=-1)L[i]=Max(Index[a[i]/j],L[i]); } } Index[a[i]]=i; } memset(Index,-1,sizeof(Index)); for(i=n;i>=1;i--){ temp=sqrt(1.0*a[i]); for(j=1;j<=temp;j++){ if(a[i]%j==0){ if(Index[j]!=-1)R[i]=Min(Index[j],R[i]); if(Index[a[i]/j]!=-1)R[i]=Min(Index[a[i]/j],R[i]); } } Index[a[i]]=i; } for(i=1;i<=n;i++) sum=(sum+(i-L[i])*(R[i]-i)%mod)%mod; printf("%d\n",sum); } return 0; }
278

被折叠的 条评论
为什么被折叠?



