标签:
?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
1 2 1 1
12
/* ***********************************************
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;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/ck_boss/article/details/47346373