Boring Sum
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1099 Accepted Submission(s): 517
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.
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.
5 1 4 2 3 9 0
136HintIn 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.
f[i]是a[i]左边最近的倍数的下标,g[i]是a[i]右边最近的倍数的下标。
用h[k],记录k的倍数上次出现的位置。求f[i]时,从左往右扫,扫到a[i]时,f[i]=h[a[i]],并且枚举出a[i]所有约数j,更新h[j]=h[a[i]/j]=i.因为枚举约数复杂度为O(sqrt(n)),对于10^5的数据,O(n*sqrt(n))能在规定时间内完成。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define maxn 100001
int f[maxn],g[maxn],a[maxn];
int h[maxn];
int main()
{
int n;
while(~scanf("%d", &n) && n){
for(int i = 1; i <= n; i++)
scanf("%d", a+i);
memset(h, 0, sizeof(h));
for(int i = 1; i <= n; i++){
f[i] = h[a[i]]? h[a[i]]:i;
for(int j = 1; j*j <= a[i]; j++)
if(a[i]%j == 0){
h[a[i]/j] = h[j] = i;
}
}
memset(h,0,sizeof(h));
for(int i = n; i > 0; i--){
g[i] = h[a[i]]?h[a[i]]:i;
for(int j = 1; j*j <= a[i]; j++)
if(a[i]%j == 0){
h[a[i]/j]=h[j] = i;
}
}
long long ans = 0;
for(int i =1; i <= n; i++)
ans += (long long)a[f[i]]*a[g[i]];
printf("%I64d\n", ans);
}
return 0;
}
376



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



