HDU 5338. First One(尺取法)

来源:互联网 发布:幼儿编程软件下载 编辑:程序博客网 时间:2024/05/16 14:10
/*采用尺取法将log2(i+j)的值相同的一起算尺取法:反复地推进区间的开头和末尾,来求满足条件的最小区间的方法注意一些细节:1<<i可能超过整数范围,可写成(1LL<<i)*/#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <ctime>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;#define INF 0x3f3f3f3f#define inf -0x3f3f3f3f#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define mem0(a) memset(a,0,sizeof(a))#define mem1(a) memset(a,-1,sizeof(a))#define mem(a, b) memset(a, b, sizeof(a))typedef long long ll;const int maxn=100010;ll a[maxn];ll sum[maxn];int main(){    int t,n,m;    scanf("%d",&t);    while(t--){        mem0(sum);        scanf("%d",&n);        for(int i=1;i<=n;i++){            scanf("%d",&a[i]);            sum[i]=sum[i-1]+a[i];        }        ll p,q;        if(sum[n]==0)            m=1;        else            m=(int)log2(sum[n]*1.0)+1;        ll ans=0;        for(int i=1;i<=m;i++){            int l=1,r=1;            if(i==1)                p=0;            else                p=1ll<<(i-1);            q=(1ll<<i);            for(int j=1;j<=n;j++){                if(l<j)                    l=j;                while(l<=n&&sum[l]-sum[j-1]<p)                        l++;                if(l==n+1){                    continue;                }                else{                    r=max(l,r);   //此时l可能等于n+1                    if(sum[r]-sum[j-1]<q){                        while(r+1<=n&&sum[r+1]-sum[j-1]<q&&sum[r+1]-sum[j-1]>=p)                            r++;                        ans+=(ll)(l+r)*(r-l+1)/2*i+(ll)j*(r-l+1)*i; //此时sum[r]-sum[j-1]>q的话一个都不满足                    }                }            }        }        printf("%I64d\n",ans);    }    return 0;}
0 0
原创粉丝点击