hdu4961 Boring Sum(数学)

31 篇文章 0 订阅

题目:

Boring Sum

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1213    Accepted Submission(s): 569


Problem Description
Number theory is interesting, while this problem is boring.

Here is the problem. Given an integer sequence a 1, a 2, …, a n, let S(i) = {j|1<=j<i, and a j is a multiple of a i}. If S(i) is not empty, let f(i) be the maximum integer in S(i); otherwise, f(i) = i. Now we define bi as a f(i). Similarly, let T(i) = {j|i<j<=n, and a j is a multiple of a i}. If T(i) is not empty, let g(i) be the minimum integer in T(i); otherwise, g(i) = i. Now we define c i as a g(i). The boring sum of this sequence is defined as b 1 * c 1 + b 2 * c 2 + … + b n * c n.

Given an integer sequence, your task is to calculate its boring sum.
 

Input
The input contains multiple test cases.

Each case consists of two lines. The first line contains an integer n (1<=n<=100000). The second line contains n integers a 1, a 2, …, a n (1<= a i<=100000).

The input is terminated by n = 0.
 

Output
Output the answer in a line.
 

Sample Input
  
  
5 1 4 2 3 9 0
 

Sample Output
  
  
136
Hint
In the sample, b1=1, c1=4, b2=4, c2=4, b3=4, c3=2, b4=3, c4=9, b5=9, c5=9, so b1 * c1 + b2 * c2 + … + b5 * c5 = 136.
 

Author
SYSU
 

Source
 

题意:给一个数组,定义f[i]是左边最靠近a[i]并且是a[i]倍数的值的下标,g[i]右边最靠近a[i]并且是a[i]倍数的值的下标,b[i]=a[f[i]],c[i]=a[g[i]],求b1*c1+b2*c2+...+bn*cn.

思路:其实就是怎么快速找出最靠近一个数并且是它倍数的数。我们可以先暴力枚举出每个数的约数(用类似素数筛法的方法,nlogn),然后用一个数组来维护一个约数最后出现的位置。先从左往右枚举数组中的每一个元素,如果它已经出现在了约数数组里,那么对应的约数数组的值就是它的左边最靠近它的倍数的下标。然后将它的左右约数填进约数数组里。再从右往左枚举数组就得到了它的右边最靠近它的倍数的下标。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int MAXN=100000;
int a[MAXN+5];
vector<int>f[MAXN+5];
int F[MAXN+5],G[MAXN+5];
int b[MAXN+5],c[MAXN+5];
void init()
{for(int i=1;i<=MAXN;i++)
f[i].clear();
for(int i=1;i<=MAXN;i++)
for(int j=i;j<=MAXN;j+=i)
f[j].push_back(i);
}
int vis[MAXN+5];
int main()
{int n;
init();
while(scanf("%d",&n)!=EOF)
{if(!n)
break;
for(int i=1;i<=n;i++)
{scanf("%d",&a[i]);
}
memset(vis,0,sizeof vis);
for(int i=1;i<=n;i++)
{if(!vis[a[i]])
{
vis[a[i]]=i;
F[i]=i;}
else
{F[i]=vis[a[i]];
vis[a[i]]=i;
}
for(int j=0;j<f[a[i]].size();j++)
{vis[f[a[i]][j]]=i;
}
}

//printf("%d ",F[i]);
//printf("\n");
memset(vis,0,sizeof(vis));
for(int i=n;i>=1;i--)
{if(!vis[a[i]])
{vis[a[i]]=i;
G[i]=i;
}
else
{G[i]=vis[a[i]];}
for(int j=0;j<f[a[i]].size();j++)
{vis[f[a[i]][j]]=i;
}

}
__int64 ans=0;
for(int i=1;i<=n;i++)
{b[i]=a[F[i]];
c[i]=a[G[i]];
ans=ans+(__int64)b[i]*c[i];
}
printf("%I64d\n",ans);

}
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值