hdu 5358 First One (2015多校第六场第6题)尺取法枚举区间和

来源:互联网 发布:js同时执行多个方法 编辑:程序博客网 时间:2024/05/21 06:54

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

题意:给你一个串数和一个公式,求这个公式的答案。

思路:直接暴力一定会超时的,而且这道题很卡时间,交C++的都TLE了。怎么优化才能不超时,于是就有了尺取法,其实就相当于两个分别指向区间左右指针不断更新区间内容的过程。

尺取法(two point)就是两个指针表示区间[l,r]的开始与结束然后根据题目来将端点移动,是一种十分有效的做法,适合连续区间的问题。

尺取法(two point)基本过程分为4步:
    1.初始化左右端点
    2.不断扩大右端点,直到满足条件
    3.如果第二步中无法满足条件,则终止,否则更新结果
    4.将左端点扩大1,然后回到第二步


代码:

#include <cstdio>#include <cstring>#include <cmath>#include <iostream>#include <algorithm>using namespace std;#define N 100005#define LL __int64int a[N];LL sum[N];int getM(LL a){    return !a?1:(int)log2(a*1.0)+1;}int main(){    int T,n,i,j,m;    LL ans,pl,pr,p;    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        ans=sum[0]=0;        for(i=1; i<=n; i++)        {            scanf("%d",&a[i]);            sum[i]=sum[i-1]+a[i];        }        m=getM(sum[n]);        for(i=1; i<=m; i++)        {            int l=1,r=0;             if(i==1)                pl=0;            else                pl=1LL<<(i-1);            pr=(1LL<<i);            for(j=1; j<=n; j++)            {                l=max(j,l);                while(l<=n&&sum[l]-sum[j-1]<pl)                    l++;                r=max(l-1,r);                while( (r+1<=n) && (sum[r+1]-sum[j-1]>=pl) && (sum[r+1]-sum[j-1]<pr) )                    r++;                if(l<=r)                    ans+=(LL)(l+r)*(r-l+1)/2*i+(LL)j*(r-l+1)*i;            }        }        printf("%I64d\n",ans);    }    return 0;}


0 0
原创粉丝点击