hdu 4961 数论 o(nlogn)

Boring Sum

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

Problem Description

Number theory is interesting, while this problem is boring.
   Here is the problem. Given an integer sequence a1, a2, …, an, let S(i) = {j|1<=j<i, and aj is a multiple of ai}. 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 af(i). Similarly, let T(i) = {j|i<j<=n, and aj is a multiple of ai}. If T(i) is not empty, let g(i) be the minimum integer in T(i); otherwise, g(i) = i. Now we define ci as ag(i). The boring sum of this sequence is defined as b1 * c1 + b2 * c2 + … + bn * cn.
   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 a1, a2, …, an (1<= ai<=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.

Source

2014 Multi-University Training Contest 9

Recommend

hujie   |   We have carefully selected several similar problems for you:  4970 4968 4967 4966 4965

题解:对于输入的数列,从前往后扫描一遍,对于每个数,都更新一下它的约数的左边最近倍数的值(b值);

同样地,从后往前扫描一遍,对于每个数,都更新一下它的约数的右边最近倍数的值(c值)。最后直接求所有b*c的和即可。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #include<map>
 9
10 #define N 100005
11 #define M 15
12 #define mod 1000000007
13 #define mod2 100000000
14 #define ll long long
15 #define maxi(a,b) (a)>(b)? (a) : (b)
16 #define mini(a,b) (a)<(b)? (a) : (b)
17
18 using namespace std;
19
20 int n;
21 ll a[N],b[N],c[N];
22 int vis[N];
23 ll ans;
24
25 int main()
26 {
27     int i;
28    // freopen("data.in","r",stdin);
29     //scanf("%d",&T);
30     //for(int cnt=1;cnt<=T;cnt++)
31     //while(T--)
32     while(scanf("%d",&n)!=EOF)
33     {
34         if(n==0) break;
35         ans=0;
36         memset(b,0,sizeof(b));
37         memset(c,0,sizeof(c));
38         memset(vis,0,sizeof(vis));
39         for(i=1;i<=n;i++){
40             scanf("%I64d",&a[i]);
41         }
42
43         vis[ a[1] ]=1;
44         for(i=2;i<=n;i++){
45             for(ll j=1;j*j<=a[i];j++){
46                 if(a[i]%j!=0) continue;
47                 if(vis[j]!=0){
48                     b[ vis[j] ]=a[i];
49                     vis[j]=0;
50                 }
51                 ll te=a[i]/j;
52                 if(vis[te]!=0){
53                     b[ vis[te] ]=a[i];
54                     vis[te]=0;
55                 }
56             }
57             vis[ a[i] ]=i;
58         }
59
60
61         for(i=1;i<=n;i++){
62             if(b[i]==0) b[i]=a[i];
63         }
64
65         memset(vis,0,sizeof(vis));
66         vis[ a[n] ]=n;
67         for(i=n-1;i>=1;i--){
68             for(ll j=1;j*j<=a[i];j++){
69                 if(a[i]%j!=0) continue;
70                 if(vis[j]!=0){
71                     c[ vis[j] ]=a[i];
72                     vis[j]=0;
73                 }
74                 ll te=a[i]/j;
75                 if(vis[te]!=0){
76                     c[ vis[te] ]=a[i];
77                     vis[te]=0;
78                 }
79             }
80             vis[ a[i] ]=i;
81         }
82
83         for(i=1;i<=n;i++){
84             if(c[i]==0) c[i]=a[i];
85         }
86
87         for(i=1;i<=n;i++){
88             ans+=b[i]*c[i];
89         }
90         printf("%I64d\n",ans);
91
92     }
93
94     return 0;
95 }

hdu 4961 数论 o(nlogn)

时间: 2024-11-17 09:16:28

hdu 4961 数论 o(nlogn)的相关文章

hdu 4542 数论 + 约数个数相关 腾讯编程马拉松复赛

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4542 小明系列故事--未知剩余系 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 889    Accepted Submission(s): 207 Problem Description "今有物不知其数,三三数之有二,五五数之有三,七七数之有

HDU - 4961 Boring Sum

Problem Description Number theory is interesting, while this problem is boring. Here is the problem. Given an integer sequence a1, a2, -, an, let S(i) = {j|1<=j<i, and aj is a multiple of ai}. If S(i) is not empty, let f(i) be the maximum integer in

hdu 4961 Boring Sum(高效)

题目链接:hdu 4961 Boring Sum 题目大意:给定ai数组; 构造bi, k=max(j|0<j<i,aj%ai=0), bi=ak; 构造ci, k=min(j|i<j≤n,aj%ai=0), ci=ak; 求∑i=1nbi?ci 解题思路:因为ai≤105,所以预先处理好每个数的因子,然后在处理bi,ci数组的时候,每次遍历一个数,就将其所有的因子更新,对于bi维护最大值,对于ci维护最小值. #include <cstdio> #include <c

hdu 1124 数论

题意:求n!中末尾连续0的个数  其实就是2*5的个数 30! 中有5 10 15 20 25 30  是5的倍数有6个   6=30/5; 6/5=1; 这个1 为25 5  10 15 20  25  30 35 40 45 50 55 60  65 70 75 80  85 90 95 100      100/5=20; 25                     50                    75                     100       20/5=4

hdu 3641 数论 二分求符合条件的最小值数学杂题

http://acm.hdu.edu.cn/showproblem.php?pid=3641 学到: 1.二分求符合条件的最小值 /*==================================================== 二分查找符合条件的最小值 ======================================================*/ ll solve() { __int64 low = 0, high = INF, mid ; while(low <=

HDU 4961 Boring Sum 暴力

题意:对于所有的A[I],同时找到左边和右边离它最近且是它的倍数的数相乘最后加起来求和. 解题思路:n*sqrt(n)的算法,开始以为过不了,wa了两发因为lld I64d对拍一个小时发现一个小时前交的代码没错只是没变I64d,..具体思路是枚举每个a[i]的因子,找离它最近的那个更新,如果已经没更新就不用更新了.用两个辅助数组记录最近的就行. 解题代码: 1 // File Name: 1002.cpp 2 // Author: darkdream 3 // Created Time: 201

HDU 4961 Boring Sum 构造题

用一个数组c, c[i]表示i这个数出现的最近数字是几. 那么当加入一个6,则 c[1] = c[2] = c[3] = c[6] = 6; ==最近怎么都要开挂啊.. #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int N = 100005; inl

2014多校训练九(HDU 4960 HDU 4961 HDU 4965 HDU 4968 HDU 4969 HDU 4970)

HDU 4960 Another OCD Patient 题意:给你一串数字  相邻x个数字合并成一个数字(相加)有一定代价  问  最少花费多少使得串变成回文串 思路: 读完题感觉像dp  数据范围也像  就开始想怎么表示状态  最简单的应该想到dp[i][j]表示i到j区间变成回文串的最小花费  状态想好了想做法  考虑将串分成AAAABBBBBBBCCC三段  即所有A合成一个数字  C也是  而且A和C相等  那么B串就变成了子问题  但是A和C是不是都要枚举呢?  这个串所有元素都是正

hdu 4961 数学杂题

http://acm.hdu.edu.cn/showproblem.php?pid=4961 先贴个O(nsqrtn)求1-n所有数的所有约数的代码: vector<int>divs[MAXN]; void caldivs() { for(int i=1;i<MAXN;i++) for(int j=i;j<MAXN;j+=i) divs[j].push_back(i); } 有了这个当时理下思路就可写了,但是重复数处理注意: 1.用一个数组vis[]  vis[i]=1表示i存在