UVALive 7501 Business Cycle

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liufengwei1/article/details/82961968

一开始队友读错题了,没看到最多减少到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;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/82961968