HDOJ 5358 First One 暴力


log2S(i,j)+1 就是S(i,j) 的二进制位数.....

枚举二进制的每一位数,计算相应的权值

具体作法就是对每个二进制位数 i ,扫一遍数组,对每个数 j 维护一个L,R 表示以该数为左端点,右端点可以在L~R的范围,这个区间内的值

加起来有 i 位二进制位数,那么这个数对答案的贡献为  设: dur = (R-L+1)  贡献值:  dur*j+(R+L)*dur/2


C++秒T , G++ 1.3s ac

First One

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


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
 

Source
 


/* ***********************************************
Author        :CKboss
Created Time  :2015年08月07日 星期五 16时48分08秒
File Name     :HDOJ5358.cpp
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>

using namespace std;

typedef long long int LL;

const int maxn=100100;

int n;
LL s[maxn];

int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);

	int T_T;
	scanf("%d",&T_T);
	while(T_T--)
	{
		scanf("%d",&n);
		for(int i=1,x;i<=n;i++)
		{
			scanf("%d",&x);
			s[i]=s[i-1]+x;
		}

		LL ans=0;

		for(int i=0;i<35;i++)
		{
			/// 在left 和 right 之间的数有(i+1)个1

			LL left=(1LL<<i);
			LL right=(1LL<<(i+1LL))-1LL;

			if(i==0) left=0LL;

			int L=1,R=1;
			for(int j=1;j<=n;j++)
			{
				/// Move L
				if(L<j) L=j;
				while(L<=n&&s[L]-s[j-1]<left) L++;

				if(L==n+1) L--;
				if(L==n&&s[L]-s[j-1]<left) break;

				if(R<L) R=L;
				/// Move R
				while(R<=n&&s[R]-s[j-1]<=right) R++;
				if(R==n+1) R--;
				if(s[R]-s[j-1]>right) R--;

				LL dur=R-L+1;
				ans=ans+(i+1LL)*(dur*j+(R+L)*dur/2LL);
			}
		}

		cout<<ans<<endl;
	}
    
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值