hdu 5358

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
  
  
1 2 1 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 __int64
int 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值