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 }
时间: 2024-08-02 10:44:03

HDU 5358 First One 数学+尺取法的相关文章

HDU 6103 Kirinriki 枚举长度 尺取法

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6103 题目描述: 定义两个相同长度的字符串的值为首尾开始字符串的ASCII相减, 求一个字符串中任取两个相同长度的不重叠的值不超过m的最大长度 解题思路: 求连续区间不超过某一个上限或者不低于某个下限的应该用尺取法 ,复杂度为O(n),  本题n是5000所以O(n^2)可行, 枚举前缀和后缀(通过枚举前缀, 再将字符串翻转枚举前缀进行), 再进行尺取 代码:  代码中有注释 #include <

(数学+尺取法)2739 - Sum of Consecutive Prime Numbers

原题链接:http://poj.org/problem?id=2739 题意:问一个数有几种方法用连续的素数和表示. 分析:其实就是很简单,先打表,然后对prime数组跑一波尺取法,如果==n就ans++. 代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 #include <cstring> 6 #include &

hdu 5358 First One 数学

链接 :http://acm.hdu.edu.cn/showproblem.php?pid=5358 First One Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 871    Accepted Submission(s): 271 Problem Description soda has an integer array a

HDU 5358 First One(枚举+尺举法)

题目链接:传送门 题意:设f(i,j)表示区间[i,j]内元素的和 ,定义 SUM(i,j) = [log2(f(i,j))+1]*(i+j) 求 sigma(sum (i,j)) ( 1<=i<=n,i<=j<=n ) 分析: log2(f(i,j))表示f(i,j)转换为2进制的长度,然后我们经过分析log2(f(i,j))+1的值域 为[1,34]然后我们枚举log2(f(i,j))+1的值,例如我们枚举其值为k,对于一个k我们找到所有满足 条件的区间(i,j),这个条件的代

Hdu 5510 Bazinga(KMP+尺取法)

题目地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=5510 思路:设两个指针l.r,对于字符串a.b.c,若a为b的子串则下次比较时可直接比较b,c.枚举r,依次比较s[l]--s[r-1]是否为s[r]的子串,若s[i]为s[r]的子串,则l++.否则答案更新为r. #include<cstdio> #include<cstring> #include<iostream> #include<algorith

HDU 5328 Problem Killer(尺取法)

You are a "Problem Killer", you want to solve many problems. Now you have nn problems, the ii-th problem's difficulty is represented by an integer aiai (1≤ai≤1091≤ai≤109). For some strange reason, you must choose some integer ll and rr (1≤l≤r≤n1

hdu 4737 A Bit Fun 尺取法

A Bit Fun Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description There are n numbers in a array, as a0, a1 ... , an-1, and another number m. We define a function f(i, j) = ai|ai+1|ai+2| ... | aj . Wher

Hdu 5358 First One (尺取法+枚举)

题目链接: Hdu 5358 First One 题目描述: 数组a有n个元素,S[i,j]定义为a[i]+a[i+1]+.....+a[j],问:这个死东西等于多少? 解题思路: 二分肯定超,这个题目的时间卡的炒鸡严格,只有n*log(n)的复杂度才能过,n*log(n)^2都不可以的. 只需要枚举K,并且枚举区间左端i值,计算K的贡献值,然后遍历时候计算一下常数相加即可. 1 #include <cstdio> 2 #include <cstring> 3 #include &

HDU 6103 Kirinriki(尺取法)

http://acm.hdu.edu.cn/showproblem.php?pid=6103 题意: 给出一个字符串,在其中找两串互不重叠的子串,计算它们之间的dis值,要求dis值小于等于m,求能选的子串的最大长度. 思路: 由于这两个子串是互不重叠的,那么这两个子串之间的间隔可以是奇数也可以是偶数,针对这两种情况我们枚举中心点,然后尺取法处理,具体看代码就懂了. 1 #include<iostream> 2 #include<algorithm> 3 #include<c