2014多校1002--hdu4961--Boring Sum

Boring Sum

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


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.

 

题目中要求计算出第i个数a[i]之前和之后距离i最近的两个a[i]的乘积(如果没有,那就选择a[i]),再把所有的乘积累加起来.

因为给出的是随机数据,所以每个数出现的概率相同,也就是说给出的a[i]大部分都会在几十,几百,或者更高,从前向后遍历,哈希出每个数出现的最近的情况,对于每一个要判断的数,从0倍开始不断增加,一直到maxn,统计所有出现过的倍数,和位置最接近那个数的点,如果没有,就记录自身,得到所有数的前面的倍数是那个,同样的方法得到后面的倍数,相乘累加。

如果a[i]是1,那么不节约时间,a[i]是10,最多用10000/10 ,a[i]是100 用时10000/100,

 

#include <cstring>
#include <cstdio>
#include <math.h>
#include <algorithm>
using namespace std;
#define LL __int64
struct node
{
    LL num, f;
}_hash[110000];
LL a[110000], b[110000], c[110000];
int main()
{
    LL n, i, j, sum, max1, mmax;
    LL ans;
    while(scanf("%I64d",&n)!=EOF&&n)
    {
        max1=-1;
        for(i=1;i<=n;i++)
        {
            scanf("%I64d",&a[i]);
            if(max1<a[i])
                max1=a[i];
        }
        for(i=1;i<=max1;i++)
            _hash[i].f=0;
        for(i=1;i<=n;i++)
        {
            mmax=-1;
            for(j=a[i];j<=max1;j+=a[i])
            {
                if(_hash[j].f)
                {
                    if(mmax<_hash[j].num)
                    {
                        mmax=_hash[j].num;
                    }
                }
            }
            _hash[a[i]].f=1;
            _hash[a[i]].num=i;
            if(mmax==-1)
                b[i]=a[i];
            else
                b[i]=a[mmax];
        }
        for(i=1;i<=max1;i++)
            _hash[i].f=0;
        for(i=n;i>=1;i--)
        {
            mmax=1e7;;
            for(j=a[i];j<=max1;j+=a[i])
            {
                if(_hash[j].f)
                {
                    if(mmax>_hash[j].num)
                    {
                        mmax=_hash[j].num;
                    }
                }
            }
            _hash[a[i]].f=1;
            _hash[a[i]].num=i;
            if(mmax==1e7)
                c[i]=a[i];
            else
                c[i]=a[mmax];
        }
        ans=0;
        for(i=1;i<=n;i++)
        {
            ans+=b[i]*c[i];
            //printf("b==%d  c==%d\n",b[i],c[i]);
        }
        printf("%I64d\n",ans);
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值