hdu 3717 二分+队列维护

思路:已知当前的总长度和为len,当前的伤害为sum,伤害次数为 num.那么对下一个点的伤害值sum=sum+2*len+num;

这个是通过(x+1)^2展开化简就能得到。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#define Maxn 100010
#define LL __int64
#define inf  1e12
using namespace std;
LL num[Maxn],cnt[Maxn],n,k;
bool OK(LL x)
{
    LL suma,sumb,ans,po,i,numa;
    LL j=n;
    suma=sumb=ans=numa=0;
    for(i=n;i>=1;i--){
        if(j>i){
        while((j-i)*(j-i)>=x){
            suma-=cnt[j]*(j-i-1)*(j-i-1);
            sumb-=cnt[j]*(j-i-1);
            numa-=cnt[j];
            j--;
        }
        }
        suma+=2*sumb+numa;
        sumb+=numa;
        if(num[i]-numa*x+suma<0) cnt[i]=0;
        else cnt[i]=(num[i]-numa*x+suma)/x+1;
        numa+=cnt[i];
        ans+=cnt[i];
    }
    return ans<=k;
}
int main()
{
    int i,j,t;
    LL mx;
    scanf("%d",&t);
    while(t--){
        scanf("%I64d%I64d",&n,&k);
        mx=0;
        for(i=1;i<=n;i++){
            scanf("%d",&num[i]);
            mx=max(mx,num[i]);
        }
        LL l,r,mid;
        l=1,r=inf;
        while(l<r){
            mid=(l+r)>>1;
            if(OK(mid))
                r=mid;
            else
                l=mid+1;
        }
        printf("%I64d\n",l);
    }
    return 0;
}

 

posted @ 2013-10-17 15:31  fangguo  阅读(285)  评论(0编辑  收藏  举报