hdu 5358

来源:互联网 发布:ubuntu配置php环境 编辑:程序博客网 时间:2024/05/04 04:32

First One

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1595    Accepted Submission(s): 488


Problem Description
soda has an integer array a1,a2,,an. Let S(i,j) be the sum of ai,ai+1,,aj. Now soda wants to know the value below:
i=1nj=in(log2S(i,j)+1)×(i+j)

Note: In this problem, you can consider log20 as 0.
 

Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains an integer n (1n105), the number of integers in the array.
The next line contains n integers a1,a2,,an (0ai105).
 

Output
For each test case, output the value.
 

Sample Input
121 1
 

Sample Output
12
 


思路 :传说中的尺取法 

            就是在一段范围内不断地找出符合条件的区间,通过不断右移左区间,来找到右区间。


            而这道题,如果直接暴力的话,肯定会超时,遇到这类题目一定要找到数目的范围想办法。

           10^10 ~~~log2(1-34) 发现如果根据i和j找到log2(sum[i,j])  的范围超时,但是如果根据

            log2(x)找出所有符合条件的i 和j 不会超时   在每一个i 对应的范围内 【l,r】都符合x 

            推算一下计算公式计算就可以了。


            这几场多校,算法不是很难,最重要的还是思路!!!


代码:

/*踏实!!努力!!*/#include<iostream>#include<stdio.h>#include<cmath>#include<cstring>#include<map>#include<queue>#include<stack>using namespace std;#define N 100005#define LL __int64int data[N];LL sum[N];int main(){    LL ans,pl,pr;    int t,n,m;    scanf("%d",&t);    while(t--){        scanf("%d",&n);        sum[0]=0;        ans=0;        for(int i=1;i<=n;i++){            scanf("%d",&data[i]);            sum[i]=sum[i-1]+data[i];        }        if(!sum[n]) m=1;        else m=(int)log2(sum[n]*1.0)+1;        for(int i=1;i<=m;i++){            int l=1,r=0;            if(i==1) pl=0;            else pl=(LL)1<<(i-1);            pr=(LL)1<<i; //注意(LL)1            for(int j=1;j<=n;j++){                l=max(l,j);                //找到左区间                while(sum[l]-sum[j-1]<pl&&l<=n)                    l++;                r=max(l-1,r);                //找到右区间                while(r+1<=n&&sum[r+1]-sum[j-1]<pr&&sum[r+1]-sum[j-1]>=pl)                    r++;                //计算公式 (log2(j,[l,r])+1)*(j+[l,r])                //        = i* (j+[l,r]) = i* j *(r-l+1) + i*(l,r)                  if(l<=r)                    ans+=(LL)(r-l+1)*(l+r)*i/2+(LL)j*(r-l+1)*i;            }        }        printf("%I64d\n",ans);    }    return 0;}

0 0