码迷,mamicode.com
首页 > 其他好文 > 详细

hdu5358First One 枚举

时间:2015-08-07 13:32:57      阅读:89      评论:0      收藏:0      [点我收藏+]

标签:美团

//给一个序列,求其所有子序列s(i,j)(i<=j)的对2取对数的再向下取整+1在乘以(i+j)的和
//枚举区间[1<<(k-1) , 1<<k),再枚举左边区间,找到右边区间的范围
//那么ans = segma(((r-l)*i + (r-l)*(r-1+l)/2)*k)(1<=k<=34)再特判断0就行 ;
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std ;
const int maxn = 100010 ;
typedef __int64 ll ;
ll sum[maxn] ;
int n,t ;
ll find(ll L , ll R)
{
    ll ans = 0 ;
    ll r = 0 , l = 0 ;
    for(int i = 1;i <= n;i++)
    {
        if(l < i)l = i ;
        if(r < i)r = i ;
        while(sum[l] - sum[i-1] < L && l <= n)l++ ;
        while(sum[r] - sum[i-1] < R && r <= n)r++;
        if(l >= r)continue ;
        ans += (r-l)*((ll)i) + (r-l)*(r-1+l)/(ll)2 ;
    }
    return ans ;
}
int main()
{
    //freopen("in.txt" ,"r" , stdin) ;
    scanf("%d" , &t) ;
    while(t--)
    {
        scanf("%d" , &n) ;
        sum[0] = 0 ;
        for(int i = 1;i <= n;i++)
        scanf("%I64d" , &sum[i]) , sum[i] += sum[i-1] ;
        ll ans = 0 ;
        ll l , r ;
        for(int k = 1;k <= 34;k++)
        {
            l = (ll)1<<(k-1) ;
            r = (ll)1<<k ;
            ans += find(l,r)*k ;
        }
        ans += find(0,1) ;
        printf("%I64d\n" ,ans) ;
    }
}






版权声明:本文为博主原创文章,未经博主允许不得转载。

hdu5358First One 枚举

标签:美团

原文地址:http://blog.csdn.net/cq_pf/article/details/47336177

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!