这题若是按常规的思路肯定会超时,我们需要注意题目中给出的每一个条件,注意有log2这个条件,s(i,j)在[2^(k-1),2^k)之间时 log2(s(i,j))下取整+1的值是k,枚举k从1到34 ,求出对应的s(i,j)在[2^(k-1),2^k)之间时i+j的和,求这个的话,可以枚举起始点从1到n,用两个指针不断后移就行
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<cstring>
using namespace std;
typedef long long ll;
const int MAX=1e5+10;
const int M=35;
int T,n;
int a[MAX];
ll sum[MAX],pw[M];
ll get_sum(ll L,ll R){ //计算[L,R)之间i+j的总和
int l=1,r=0;
ll SUM=0;
for(int i=1;i<=n;i++){
if(l<i) l=i;
if(r<i-1) r=i-1;
while(l<=n && sum[l]-sum[i-1]<L) l++; //计算第一个l,使得sum[i~l]>=L
while(r+1<=n && sum[r+1]-sum[i-1]<R) r++; //计算第一个r,是的sum[i~r]<R
if(l>r) continue;
if(sum[l]-sum[i-1]<L || sum[l]-sum[i-1]>=R) continue;
if(sum[r]-sum[i-1]<L || sum[r]-sum[i-1]>=R) continue;
SUM += ((ll)(r-l+1)*i+(ll)(l+r)*(r-l+1)/2); //区间大小为r-l+1,里面有r-l+1个i,至于j,它的值为[l,r],所以总和为(l+r)*(r-l+1)/2
}
return SUM;
}
int main()
{
ll SUM=0,mm,m;
scanf("%d",&T);
while(T--)
{
int t;
SUM=0;
memset(sum,0,sizeof(sum));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
sum[i]=sum[i-1]+a[i];
}
for(int i=0;i<M;i++)
pw[i]=pow(2,i);
for(int i=1;i<=34;i++){
SUM = SUM + (ll)i*get_sum(pw[i-1],pw[i]); //i=i-1+1,即题中的log2*S(i,j)+1
}
SUM += get_sum(0,1);
printf("%I64d\n",SUM);
}
return 0;
}