2015多校第6场 HDU 5358 First One 枚举,双指针

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5358

题意:如题。

解法:观察式子发现,由于log函数的存在,使得这个函数的值域<=34,然后我们枚举这个值域,对于这个值域,我们用双指针O(n)维护值前缀和在这个值域里面的区间,计算即可。

 

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005;
typedef long long LL;
LL l[35], r[35], sum[maxn];
LL a, b, num, ans;
int main()
{
    l[0] = 0;
    r[0] = 1;
    for(int i=1; i<=34; i++){
        l[i] = (1LL<<i);
        r[i] = ((1LL<<(i+1))-1LL);
    }
    int T, n;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        memset(sum, 0, sizeof(sum));
        for(int i=1; i<=n; i++){
            int x;
            scanf("%d", &x);
            sum[i] = sum[i-1]+x;
        }
        ans = 0;
        for(int i=1; i<35; i++){
            if(sum[n]<l[i-1]) break;
            a = 1, b = 0;
            num = 0;
            for(LL j=1; j<=n; j++){
                a = max(a, j);
                while(a<=n&&sum[a]-sum[j-1]<l[i-1]) a++;
                b = max(b, a-1);
                while(b+1<=n&&sum[b+1]-sum[j-1]>=l[i-1]&&sum[b+1]-sum[j-1]<=r[i-1]) b++;
                if(a<=b) num += (b-a+1)*j+(b+a)*(b-a+1)/2;
            }
            ans += num*i;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

 

posted @ 2017-08-12 10:37  zxycoder  阅读(202)  评论(0编辑  收藏  举报