一开始队友读错题了,没看到最多减少到0,于是以为是道水题,队友Wa了以后我才发现少看个条件,就说这道题怎么这么久才一个人做。
sum为一轮数字的前缀和
首先是加入p<=2*n或者sum[n]<=0的时候
那么直接二分答案在前min(2*n,p)中跑
为什么是2*n呢
不能小于0就要考虑一些问题,3个数,1 -6 8,此时sum[n]>0
我们发现前缀和sum的值是1 -5 3,那么我们找到前缀和最小的那个地方,从那个位置后面开始,一定是正数,那么到-5的时候变成0,然后走8 1=9,达到最大值,所以要走2*n
然后我们考虑找sum[1-n]中的mini,如果mini>=0的话,说明永远不会出现不能小于0的情况,那么此时直接求最大值
circlenum表示最多走多少圈,rest表示走了circlenum圈后还剩多少步,但还要考虑一种情况,就是少走最后一圈但是取到1-n中很大的前缀和,和走最多圈在1-rest选一个小的前缀和,两种情况比较一下大小,得到最大值,然后g-maxval得到ans的最小值
如果mini<0的话,你一开始带0-(-mini)都是没有意义的,因为你到mini=0了,相当于从mini之后重新开始,于是我们就先判断一蛤0是否可行,不可行的话就从mini位置之后一个的st到p,然后求一遍上面的maxval,只是少了几步,然后g-maxval比较一下,得到ans的最小值。
分的情况有点多,感觉有一些情况有点重复,或者能更一般的解决,不过写完1A还是挺舒服的,然而这场还是雪崩了,各种水题没写出来
emacs里的代码复制出来格式有点奇怪 = =
#include<bits/stdc++.h>
#define maxl 100010
using namespace std;
long long n,g,p,ans,cas;
long long a[maxl*2],sum[maxl*2];
inline void prework()
{
scanf("%lld%lld%lld",&n,&g,&p);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
sum[i]=sum[i-1]+a[i];
}
for(int i=n+1;i<=2*n;i++)
a[i]=a[i-n],sum[i]=sum[i-1]+a[i];
}
inline bool jug(long long mid,long long len)
{
if(mid>=g)
return true;
for(int i=1;i<=len;i++)
{
if(mid+a[i]<0)
mid=0;
else
mid=mid+a[i];
if(mid>=g)
return true;
}
return false;
}
inline long long find(long long len)
{
long long l=0,r=g,mid;
while(l+1<r)
{
mid=(l+r)>>1;
if(jug(mid,len))
r=mid;
else
l=mid;
}
if(jug(l,len))
return l;
else
return l+1;
}
inline void mainwork()
{
if(p<=2*n || sum[n]<=0)
{
ans=find(min(2*n,p));
return;
}
long long once=sum[n],mini=1ll<<62,st,l,r,mid;
for(int i=1;i<=n;i++)
if(mini>sum[i])
{
mini=sum[i];
st=i+1;
}
if(mini>=0)
{
long long circlenum=p/n,rest=p%n,least=g/sum[n];
if(g%sum[n]) ++least;
if(circlenum>=least)
{
ans=0;
return;
}
long long mx=0,MX=0,maxval;
for(int i=1;i<=rest;i++)
mx=max(sum[i],mx);
for(int i=1;i<=n;i++)
MX=max(sum[i],MX);
maxval=max(circlenum*sum[n]+mx,(circlenum-1)*sum[n]+MX);
if(maxval>=g)
ans=0;
else
ans=g-maxval;
return;
}
else
{
long long tmp=0,stmx=0;bool flag=true;
for(int i=st;i<=st+n-1;i++)
{
tmp+=a[i];
if(tmp>stmx)
stmx=tmp;
if(tmp<0)
tmp=0,flag=false;
}
if(flag)
{
int circlenum=(p-st+1)/n,rest=(p-st+1)%n;
long long mx=0,MX=0,maxval;
for(int i=st;i<=st+rest-1;i++)
mx=max(sum[i]-sum[st-1],mx);
for(int i=st;i<=st+n-1;i++)
MX=max(sum[i]-sum[st-1],MX);
maxval=max(circlenum*sum[n]+mx,(circlenum-1)*sum[n]+MX);
if(maxval>=g)
{
ans=0;
return;
}
}
else
{
if(stmx>=g)
{
ans=0;
return;
}
}
int circlenum=p/n,rest=p%n;
if(circlenum>g/sum[n])
{
ans=0;
return;
}
long long mx=0,MX=0,maxval;
for(int i=1;i<=rest;i++)
mx=max(sum[i],mx);
for(int i=1;i<=n;i++)
MX=max(sum[i],MX);
maxval=max(circlenum*sum[n]+mx,(circlenum-1)*sum[n]+MX);
if(g-maxval<(-mini))
ans=-mini;
else
ans=g-maxval;
}
}
inline void print()
{
printf("Case #%lld: %lld\n",cas,ans);
}
int main()
{
int t;
// freopen("B.in","r",stdin);
scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}