题意:
计算 其中 , 表示 的和。
分析:
因为 表示每个数的二进制有多少位, 并且最大的数也只有34位,所以根据这个条件进行尺取,复杂度 尺取计算满足当前位的条件下每个(i+j) 的和,每对应一个i值,利用尺取法求出满足条件的j值的范围,则
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
ll ans;
ll pw[40];
ll pre[maxn];
ll a[maxn];
int n;
ll get_sum(ll L,ll R){ //计算[L,R)中i+j的和
int l=1,r=1;
ll res=0;
for(int i=1;i<=n;i++){
l=max(l,i);r=max(r,i);
while(l<=n&&pre[l]-pre[i-1]<L) l++;
while(r<=n&&pre[r]-pre[i-1]<R) r++;
r--;
if(l>r) continue;
if(pre[l]-pre[i-1]>=R||pre[l]-pre[i-1]<L) continue;
if(pre[r]-pre[i-1]<L||pre[r]-pre[i-1]>=R) continue;
res+=(ll)(r-l+1)*(ll)i+(ll)(r-l+1)*(l+r)/2;
}
return res;
}
int main(){
int T;
scanf("%d",&T);
for(int i=0;i<35;i++){
pw[i]=1ll<<i;
}
while(T--){
scanf("%d",&n);
pre[0]=0;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
pre[i]=pre[i-1]+a[i];
}
ans=0;
for(int i=1;i<35;i++){
ans+=(ll)i*get_sum(pw[i-1],pw[i]);
}
ans+=get_sum(0,1);
printf("%lld\n",ans);
}
return 0;
}