HDU 5358 First One 数学+尺取法

多校的题,摆明了数学题,但是没想出来,蠢爆了,之前算了半天的s[i][j]的和,其实是积。其实比赛的时候我连log(s[i][j])+1是s[i][j]的位数都没看出来,说出来都丢人。

知道了这个之后,就枚举二进制数的每一位,因为元素都是非负数,所以sum数组是非降的,这里用到了尺取法,之前也是听说过,应该是做过吧,不太记得了。

因为[2k-1,2k)的位数是k,枚举时,固定左端点,在sum数组找到最小的大于等于2k-1,最大的小于2k的点,这中间的点和左端点的s[i][j]就对于当前的k满足条件了,就把这些答案加到答案中,复杂度就是O(nlogn)

其实我的代码并没有AC,一直是超时,但是我做了一些极限的数据在本机上也是秒出,当然是我程序的原因,不过我现在还不知道怎么回事,花了这么多时间了,就这样吧。

哈哈原来是编译器的问题,之前交的C++,刚交了发G++就A了,

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <fstream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <deque>
 7 #include <vector>
 8 #include <queue>
 9 #include <string>
10 #include <cstring>
11 #include <map>
12 #include <stack>
13 #include <set>
14 #define LL long long
15 #define INF 0x3f3f3f3f
16 #define OPEN_FILE
17 #define MAXN 100005
18 using namespace std;
19 LL sum[MAXN], p[MAXN];
20 LL ans;
21 int main()
22 {
23 #ifdef OPEN_FILE
24     freopen("in.txt", "r", stdin);
25     //freopen("out.txt", "w", stdout);
26 #endif // OPEN_FILE
27     int T;
28     scanf("%d", &T);
29     p[0] = 0;
30     p[1] = 2;
31     for(int i = 2; i <= 34; i++){
32         p[i] = p[i - 1] * 2;
33     }
34     for(int cas = 1; cas <= T; cas++){
35         int n;
36         scanf("%d", &n);
37         memset(sum, 0, sizeof(sum));
38         int x;
39         for(int i = 1; i <= n; i++){
40             scanf("%d", &x);
41             sum[i] = sum[i - 1] + x;
42         }
43         ans = 0;
44         for(int i = 0; i <= 33; i++){
45             LL left = 1, right = 1;
46             for(int j = 1; j <= n; j++){
47                 left = max((LL)j, left);
48                 right = max((LL)j, right);
49                 while(left <= n && sum[left] - sum[j - 1] < p[i]){
50                     left++;
51                 }
52                 //int right = left;
53                 while(right <= n && sum[right] - sum[j - 1] < p[i + 1]){
54                     right++;
55                 }
56                 right--;
57                 if(right > n){
58                     right = n;
59                 }
60                 if(left <= right){
61                     ans += ((((left + right)*(right - left + 1)) / 2) + (right - left + 1) * j)  * (LL)(i + 1);
62                 }
63             }
64             if(p[i + 1] > sum[n]){
65                 break;
66             }
67         }
68         printf("%I64d\n", ans);
69     }
70 }

 

posted on 2015-08-07 22:25  张济  阅读(158)  评论(0编辑  收藏  举报

导航