⌊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; }