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; }