多校第六场 1006 hdu 5358 First One(枚举)

题目链接:

[hdu 5358] (http://acm.hdu.edu.cn/showproblem.php?pid=5358)

题目大意:

给出一个公式:
多校第六场 1006 hdu 5358 First One(枚举)_第1张图片
求解即可

题目分析:

  • 我们定义loc[i][j]为在左边界在i且设区间为sum, log2(sum) 的右边界。
  • 定义 lent t=log2(sum) 时候的长度
  • 原式
    =i=1nt=0log2S(i,n)maxj=in{j|log2S(i,j)=t}(len(2jlen+1)2+ilen)=i=1nt=0log2S(i,n)loc[i][t](len(2jlen+1)2+ilen)
  • 那么预处理出loc[i][j],我们就可以在 O(nlogsum2) 的时间内解决这个问题。
  • 预处理loc[i][j]我们采取枚举每一个j,然后扫描数组,利用前缀和递增的性质,可以通过两个指针,一个指针指向区间的头,一个指针指向区间的尾,扫描一遍获得loc[i][j]的值。复杂度 O(nlogsum2)

AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAX 100007

using namespace std;

typedef long long LL;

LL a[MAX];
LL loc[MAX][35];
int t,n;

void init ( )
{
    a[n] = 0;
    LL cmp = 2LL;
    for ( LL i = 0 ; i < 34 ; i++ )
    {
        LL sum = a[0];
        int r = 0;
        for ( int l = 0 ; l < n ; l++ )
        {
            if (l)
                sum -= a[l-1];
            while ( sum < cmp && r < n )
            sum += a[++r];
            loc[l][i] = r;
        }
        cmp <<= 1;
    }
}

void solve ()
{
    LL ans = 0;
    for ( LL i = 0 ; i < n ; i++ )
    {
        LL ii = i;
        for ( LL j = 0 ; j < 34 ; j++ )
        {
            LL x = loc[i][j];
            LL len = x-ii;
            ans += ((i+1)* len + (x+1+ii)*len/2LL)*(j+1);
            ii = x;
        }
    }
    printf ( "%I64d\n" , ans );
}

int main ( )
{
    scanf ( "%d" , &t );
    while ( t-- )
    {
        scanf ("%d" , &n );
        for ( int i = 0 ; i < n ; i++ )
            scanf ("%I64d" , &a[i] );
        init ();
        solve();
    }
}

你可能感兴趣的:(枚举,数学,HDU,多校)