码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 5358 First One 求和(序列求和,优化)

时间:2015-08-07 23:53:44      阅读:230      评论:0      收藏:0      [点我收藏+]

标签:

 

 

题意:给定一个含n个元素的序列,求下式子的结果。S(i,j)表示为seq[i...j]之和。注:对于log20可视为1。数据量n<=105

 

技术分享

 

思路:即使能够在O(1)的时间内求得任意S,也是需要O(n*n)来求和的。

  对于这种题,一般就是研究式子,看有什么办法可以减少复杂度。

  对于这个式子,S最大也不会超过longlong,确切计算,小于234。那么log的范围这么小,如果能够知道分别有多少个的话,那就快多了。可以看得出对于同一个i,log的结果是线性的,从1到34逐步递增的。那很好办,对于每个i,只需要将一整段给截出来,统计(i,j)之和再乘以logx即可。那么1~n最多可以截成34段啦。相比而言快了许多。复杂度为O(34*n)。

  但是本题连这样的复杂度还是不行,还能继续优化,设技术分享为k,穷举k,再穷举i,对于每个i,假设i-1中(L,R)这一段的结果为k,而i的对应段大于等于这段。所以只需从上次穷举完之处继续判断即可。很难说清,看代码注释吧。

 

 

 

 

技术分享
 1 #include <bits/stdc++.h>
 2 #define INF 0x7f7f7f7f
 3 #define pii pair<int,int>
 4 #define LL long long
 5 using namespace std;
 6 const int N=100100;
 7 LL sum[N], up[50];
 8 int cur[N];
 9 void pre_cal()
10 {
11     sum[0]=0;
12     for(int i=0; i<40; i++)    up[i]= (LL)1<<i;
13 }
14 LL cal(int n)
15 {
16     for(int i=0; i<=n; i++) cur[i]=i;   //记录以i为下标的,穷举到那里了。
17 
18     LL ans=0;
19     int L=1, R=1;
20     for(int k=0; k<35; k++)
21     {
22         R=cur[1];
23         for(int i=1; i<=n; i++) //以i为下标的
24         {
25             L=cur[i];
26             R=max(cur[i], cur[i-1]);     //这一步决定了AC或者TLE
27             if(L>n) continue;            //以i为下标的已经计算完毕。
28 
29             while( R<=n &&  sum[R]-sum[i-1]<up[k] )    R++;     //找到(logx+1)为k的一段[L,R)
30             if(L<R)
31             {
32                 cur[i]=R;
33                 if((R-L)&1)          ans+=( (LL)(R-L)*i + (LL)(R-1+L)/2*(R-L) )*max(1,k);   //注意这里千万要转longlong
34                 else                 ans+=( (LL)(R-L)*i + (LL)(R-1+L)*(R-L)/2 )*max(1,k);
35             }
36         }
37     }
38 
39     return ans;
40 }
41 
42 int main()
43 {
44     freopen("input.txt", "r", stdin);
45     pre_cal();
46     int t, n;
47     scanf("%d", &t);
48     while(t--)
49     {
50         scanf("%d", &n);
51         for(int i=1; i<=n; i++)
52         {
53             scanf("%lld", &sum[i]);
54             sum[i] += sum[i-1];
55         }
56         printf("%lld\n", cal(n));
57     }
58     return 0;
59 }
AC代码

 

HDU 5358 First One 求和(序列求和,优化)

标签:

原文地址:http://www.cnblogs.com/xcw0754/p/4712257.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!