hdu 5358 First One (尺取法)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5358

题意:

分析:首先要知道[log2(x)]+1代表x的位数,而且根据题意不会超过35,那么枚举位数i:1~35。对于每一位i找到区间[x,y],使得S(x,y)的二进制表示的位数等于i,此时的贡献为i*(x+y)。那么对于每一个i,怎么找出所有符合条件的区间[x,y]?1~n枚举起点x,那么y会在一段范围[l,r]内满足条件。下次x变成x+1,即起点x向右移位,那么现在要找的y的区间为[l‘,r‘],l‘不至于小于l同样r‘不至于小于r。这样可以用O(n)的复杂度找出所有区间使得区间和的二进制表示的位数为枚举的i。总的时间复杂度为35*N。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int maxn = 1e5+6;
LL pow2l[50],pow2r[50],s[maxn];
int main()
{
	for(int i=1;i<=40;i++)
	{
		pow2l[i]=(1ll<<i);
		pow2r[i]=((1ll<<(i+1))-1);
	}
	pow2l[0]=0;
	pow2r[0]=1;
	int ncase,i,j,n,x;
	scanf("%d",&ncase);
	while(ncase--)
	{
		scanf("%d",&n);
		for(i=1;i<=n;i++)
		{
			scanf("%d",&x);
			s[i]=s[i-1]+x;
		}
		LL ans=0;
		for(i=1;i<=35;i++)
		{
			if(s[n]<pow2l[i-1])
				break;
			LL l=1,r=0,temp=0;
			for(j=1;j<=n;j++)
			{
				l=(l>j?l:j);
				while(l<=n && s[l]-s[j-1]<pow2l[i-1])
					l++;
				r=(r>l-1?r:l-1);
				while(r+1<=n && s[r+1]-s[j-1]>=pow2l[i-1] && s[r+1]-s[j-1]<=pow2r[i-1])
					r++;
				if(r>=l)
					temp+=(r-l+1)*j+(r+l)*(r-l+1)/2;
			}
			ans+=temp*i;
		}
		printf("%I64d\n",ans);
	}
	return 0;
}
时间: 2024-08-07 08:37:25

hdu 5358 First One (尺取法)的相关文章

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

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满足条

HDU 6103 Kirinriki 枚举长度 尺取法

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

HDU 6119 小小粉丝度度熊 【预处理+尺取法】(2017&quot;百度之星&quot;程序设计大赛 - 初赛(B))

小小粉丝度度熊 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1572    Accepted Submission(s): 513 Problem Description 度度熊喜欢着喵哈哈村的大明星--星星小姐. 为什么度度熊会喜欢星星小姐呢? 首先星星小姐笑起来非常动人,其次星星小姐唱歌也非常好听. 但这都不是最重要的,最重要的是

hdu 5371 Hotaru&#39;s problem(manacher+尺取法)

题意: 给定一个有n个数字的序列,找出一个连续的子序列满足这样的条件: 1. 平均分成三段 2. 第一段与第三段一样 3. 第二段是第一段的倒序.求这样的子序列的最大长度. 数据范围:n~100000 解析: 我看网络上面很多的题解都是用O(n2/32)的做法水数据过去的,这种做法是先用mancher算法预处理出每个每个回文串最远所能抵达的位置,然后枚举每个位置i,再枚举其回文串的长度,然后枚举当前位置i到回文串所能抵达的最远距离,判断途径的位置j是,否有回文串能够到当前位置i.但是这种做法的复

HDU 5672 String 尺取法追赶法

String Problem Description There is a string S.S only contain lower case English character.(10≤length(S)≤1,000,000)How many substrings there are that contain at least k(1≤k≤26) distinct characters? Input There are multiple test cases. The first line

HDU 5806 NanoApe Loves Sequence Ⅱ ——(尺取法)

题意:给出一个序列,问能找出多少个连续的子序列,使得这个子序列中第k大的数字不小于m. 分析:这个子序列中只要大于等于m的个数大于等于k个即可.那么,我们可以用尺取法写,代码不难写,但是有些小细节需要注意(见代码注释).我觉得,<挑战程序设计>里的尺取法的内容需要好好的再回顾一下= =. 代码如下: 1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 using namesp

HDU 6205(尺取法)2017 ACM/ICPC Asia Regional Shenyang Online

题目链接 emmmm...思路是群里群巨聊天讲这题是用尺取法.....emmm然后就没难度了,不过时间上3000多,有点.....盗了个低配本的读入挂发现就降到2800左右, 翻了下,发现神犇Claris280MS秒过.......%%% #include <stdio.h> #include <stdlib.h> #include <cmath> #include <string.h> #include <iostream> #include