给出一个序列A,对于A里面的每个元素,左边最近的能被它整除的元素记为B序列对应位置的,右边最近的是它的整数倍的元素记为C序列对应位置,找不到的记它本身,最后算出对应位置B*C的总和。
容器模拟,按顺序扫一遍,每次如果有符合条件的取出来,即为最近的。最后把它的下标放到对应位置的容器中,然后倒序求一遍,最后求和。
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <iomanip>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn=100010;
vector<int>p[maxn];
int n;
int a[maxn];
int b[maxn];
int c[maxn];
int main()
{
while(scanf("%d",&n)!=EOF)
{
if(n==0)
{
break;
}
for(int i=0;i<maxn;i++)
{
p[i].clear();
}
memset(b,-1,sizeof(b));
memset(c,-1,sizeof(c));
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
c[n-1]=n-1;
p[a[0]].push_back(0);
for(int i=1;i<n;i++)
{
for(int j=1;j<=sqrt(a[i]);j++)
{
int u=j;
if(a[i]%j==0)
{
for(int k=0;k<p[u].size();k++)
{
c[p[u][k]]=i;
}
p[u].clear();
int v=a[i]/j;
for(int k=0;k<p[v].size();k++)
{
c[p[v][k]]=i;
}
p[v].clear();
}
}
p[a[i]].push_back(i);
}
for(int i=0;i<maxn;i++)
{
p[i].clear();
}
b[0]=0;
p[a[n-1]].push_back(n-1);
for(int i=n-2;i>=0;i--)
{
for(int j=1;j<=sqrt(a[i]);j++)
{
int u=j;
if(a[i]%j==0)
{
for(int k=0;k<p[u].size();k++)
{
b[p[u][k]]=i;
}
p[u].clear();
int v=a[i]/j;
for(int k=0;k<p[v].size();k++)
{
b[p[v][k]]=i;
}
p[v].clear();
}
}
p[a[i]].push_back(i);
}
for(int i=0;i<n;i++)
{
if(b[i]==-1)
{
b[i]=i;
}
if(c[i]==-1)
{
c[i]=i;
}
}
long long sum=0;
for(int i=0;i<n;i++)
{
sum+=(long long)a[b[i]]*a[c[i]];
}
printf("%I64d\n",sum);
}
return 0;
}