#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;
}
hdu5358(尺取法)
這題若是按常規的思路肯定會超時,我們需要注意題目中給出的每一個條件,注意有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,用兩個指針不斷後移就行
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.