二分,对于能贡献到位置 (j) 的子弹,拆式子:
[sum p-(i_x-j)^2
]
[sum p-i_x^2+2 imes i_x imes j-j^2
]
[tot imes(p-j^2)-sum i_x^2+2 imes j imessum i_x
]
因为每次 check
贡献的范围是一样的,从后往前依次打死,差分维护最后定长区间中的子弹数量、威力值和、威力值平方和。
code:
#include<bits/stdc++.h>
using namespace std;
#define N 1000005
#define Min(x,y)((x)<(y)?x:y)
#define For(i,x,y)for(i=x;i<=(y);i++)
#define Down(i,x,y)for(i=x;i>=(y);i--)
#define int long long
int x[N],y[N],z[N],m[N],n,k;
int read()
{
int A;
bool K;
char C;
C=A=K=0;
while(C<'0'||C>'9')K|=C=='-',C=getchar();
while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar();
return(K?-A:A);
}
bool check(int p)
{
int len=Min(sqrt(p),n),i,xx,yy,zz,tmp,res;
xx=yy=zz=res=0;
For(i,1,n<<1)x[i]=y[i]=z[i]=0;
Down(i,n,1)
{
tmp=m[i]-(xx*(p-i*i)-yy+(i*zz<<1));
xx-=x[i+len];
yy-=y[i+len];
zz-=z[i+len];
if(tmp<0)continue;
tmp=tmp/p+(tmp%p>0);
res+=tmp;
x[i]+=tmp;
xx+=x[i];
y[i]+=i*i*tmp;
yy+=y[i];
z[i]+=i*tmp;
zz+=z[i];
if(res>k)return 0;
}
return 1;
}
signed main()
{
int i,l=1,r=10000000000000000ll,mid;
n=read(),k=read();
For(i,1,n)m[i]=read()+1;
while(l<r)
{
mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}
cout<<l;
return 0;
}