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;

}

 

你可能感兴趣的:(HDU)