ACDream - Divide Sum

先上题目:

Divide Sum

Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
SubmitStatus

Problem Description

long long ans = 0;
for(int i = 1; i <= n; i ++)
    for(int j = 1; j <= n; j ++)
        ans += a[i] / a[j];
给出n,a[1]...a[n],求ans

Input

不超过5组数据,每组数据:

第一行n(1 <= n <= 10^5)

第二行n个数,a[1].. a[n] (1 <= a[i] <= 10^5)

Output

每组数据一行,ans

Sample Input

5
1 2 3 4 5

Sample Output

27

  比赛的时候想的方法是枚举除数的倍数,然后用lower_bound和upper_bound求出那个范围里面的得到同一个商的数的个数,然后相乘得到一部分的结果,结果超时了。后来在思考一下,发现好像时间复杂度并没有降到nlogn而是变成了(n^2)logn,然后就想到的另一种nlogn的方法,但是在脑子想出来的时候觉得跟之前的方法基本一样,时间复杂度并没有任何变化。结果比赛结束前基本没有动过,结束以后听题解,结果ZZ说的方法就是我想的那种······又被坑了一回,这回也是自己坑自己。

  思路:先对所有的数按从小到大排序,然后根据分析我们可以发现,如果一个数除以一个比它大的数,那么结果绝对为0,而一个数被比它大的数除的时候,我们可以枚举这个除数的倍数,然后得到在某一倍数的范围里面的数的个数,将个数乘以枚举的商,在求和就是答案了。比赛的时候求范围里面的数的个数我用的方法是求上下界然后相减求个数,结果TLE了3次,ZZ将的方法是用树状数组统计,这个我在比赛的时候也有想过,但是觉得枚举的环节比较耗时间所以就没有动手写。

  总的来说前6场个人赛有不少都是自己坑自己,不少的题都是会做的,结果要么因为敲了代码以后,一直觉得是代码没有问题,但是一直WA或者TLE以后就觉得是思路有问题,最终的结果是有几场吃了蛋,剩下的几场也是被吊打啊T_T。感觉暑假开始以后就一直很没有状态,敲一段代码都错漏百出,有的时候真的感觉没脸见人了(捂脸)。看来要快点加油才行啊。

上代码:

 1 /*
 2 * this code is made by sineatos
 3 * Problem: 1181
 4 * Verdict: Accepted
 5 * Submission Date: 2014-07-31 23:29:05
 6 * Time: 428MS
 7 * Memory: 1868KB
 8 */
 9 #include <cstdio>
10 #include <cstring>
11 #include <algorithm>
12 #define lowbit(x) (x&(-x))
13 #define MAX 100002
14 #define ll long long
15 using namespace std;
16  
17 int a[MAX];
18 int c[MAX];
19 int n;
20  
21 const int all=MAX-2;
22  
23 void add(int x,int e){
24     for(;x<=all;x+=lowbit(x)){ c[x]+=e; }
25 }
26  
27 int sum(int x){
28     int ans=0;
29     for(;x>0;x-=lowbit(x)) ans+=c[x];
30     return ans;
31 }
32  
33 int main()
34 {
35     ll sum0,ans,lans;
36     //freopen("data.txt","r",stdin);
37     while(scanf("%d",&n)!=EOF){
38         memset(c,0,sizeof(c));
39         sum0=0;
40         for(int i=0;i<n;i++){
41             scanf("%d",&a[i]);
42             add(a[i],1);
43             sum0+=a[i];
44         }
45         sort(a,a+n);
46         ans=0;
47         lans=0;
48         for(int i=0;i<n;i++){
49             if(a[i]==1){
50                 ans+=sum0;
51             }else if(i!=0 && a[i]==a[i-1]){
52                 ans+=lans;
53             }else{
54                 int k,e=1;
55                 lans=0;
56                 for(int j=a[i];j<=a[n-1];j+=a[i]){
57                     k=j+a[i];
58                     if(k>a[n-1]) k=a[n-1]+1;
59                     int q=sum(k-1)-sum(j-1);
60                     lans+=(ll)q*e;
61                     e++;
62                 }
63                 ans+=lans;
64             }
65         }
66         printf("%lld\n",ans);
67     }
68     return 0;
69 }
/*Divide Sum*/

 

posted @ 2014-07-31 23:45  海拉鲁的林克  阅读(188)  评论(0编辑  收藏  举报