HDU5358-First One

First One

                                                                      Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
                                                                                              Total Submission(s): 2612    Accepted Submission(s): 745


Problem Description
soda has an integer array  a1,a2,,an . Let  S(i,j)  be the sum of  ai,ai+1,,aj . Now soda wants to know the value below:
i=1nj=in(log2S(i,j)+1)×(i+j)

Note: In this problem, you can consider  log20  as 0.
 

Input
There are multiple test cases. The first line of input contains an integer  T , indicating the number of test cases. For each test case:

The first line contains an integer  n   (1n105) , the number of integers in the array.
The next line contains  n  integers  a1,a2,,an   (0ai105) .
 

Output
For each test case, output the value.
 

Sample Input
  
  
1 2 1 1
 

Sample Output
  
  
12
 

Author
zimpha@zju
 

Source
 

Recommend
wange2014
 

题意:给你一个整数序列a1,a2,a3,…,an,要求求出的值,S(i,j)表示ai+ai+1+ai+2+…+aj
解题思路:(⌊log2S(i,j)⌋+1)的意思就是S(i,j)化成二进制后的比特位个数,因为S(i,j)不超过10^10,所以比特位不会超过35个。先初始化数组pow2,记录比特位为i的所有数中的第一个数,然后用尺取法枚举每一位有多少个


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <bitset>
#include <set>
#include <vector>
#include <functional>

using namespace std;

#define LL long long
const int INF = 0x3f3f3f3f;

int n;
LL sum[100090], a[100090];
LL pow2[40];

int main()
{
	pow2[1] = 0, pow2[2] = 2;
	for (int i = 3; i<40; i++)
		pow2[i] = pow2[i - 1] << 1;
	int t;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d", &n);
		sum[0] = 0;
		for (int i = 1; i <= n; i++) scanf("%lld", &a[i]), sum[i] = sum[i - 1] + a[i];
		LL ans = 0, temp;
		for (int i = 1; i <= 39; i++)
		{
			if (pow2[i]>sum[n]) break;
			int l = 1, r = 0;
			temp = 0;
			for (int j = 1; j <= n; j++)
			{
				l = max(l, j), r = max(r, j-1);
				while (l <= n&&sum[l] - sum[j - 1]<pow2[i]) l++;
				while (r + 1 <= n&&sum[r + 1] - sum[j - 1]<pow2[i + 1]) r++;
				if (l <= r) temp +=1LL* (r - l+1)*(r + l ) / 2 + 1LL*j*(r - l + 1);
			}
			ans +=1LL* temp*i;
		}
		printf("%lld\n", ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值