题解 CF1490G 【Old Floppy Drive】

绝顶我为峰

2021-02-17 14:31:47

Solution

显然每走一圈贡献是一定的,计算一下前缀和即可。 记前缀和为 $sum[i]$,$maxn[i]$ 为 $a[1]\sim a[i]$ 的起点为 1 的子串权值最大值,显然有 $maxn[i]=\max(maxn[i-1],sum[i])$。 第一圈就满足要求的($maxn[n]\geq x$)可以特殊处理一下,这样特判的时候不容易出错。 然后特判无解,充要条件 $sum[n]\leq0$ 且 $x>0$。 剩下来的就是走了不止 1 圈的情况。我们可以二分圈数,每次 check 走 $mid+1$ 圈后能否满足条件,即 $sum[n]\times mid+maxn[n]\geq x$(因为第 $mid+1$ 圈可能走到图中就满足条件所以最后一圈贡献并不是 $sum[n]$ 而是 $maxn[n]$)。 然后二分得到圈数 $ans+1$,那么显然前 $ans$ 圈是走完整的,而最后一圈不一定,于是在 $maxn[]$ 数组上二分就好了,答案为$ans\times n+lower\_bound(maxn+1,maxn+n+1,x-ans\times sum[n])-maxn-1$。 ```cpp #include<iostream> #include<cstdio> #include<algorithm> using namespace std; #define int long long int t,n,m,a[200001],sum[200001],maxn[200001]; signed main() { scanf("%lld",&t); while(t--) { scanf("%lld%lld",&n,&m); maxn[0]=-1e18; sum[0]=0; for(register int i=1;i<=n;++i) { scanf("%lld",&a[i]); sum[i]=sum[i-1]+a[i]; maxn[i]=-1e18; maxn[i]=max(maxn[i-1],sum[i]); } while(m--) { int x; scanf("%lld",&x); if(maxn[n]>=x) { printf("%lld ",(long long)(lower_bound(maxn+1,maxn+n+1,x)-maxn-1)); continue; } if(sum[n]<=0&&x>0) { printf("-1 "); continue; } int l=0,r=1e9,mid,ans=1e9; while(l<r) { mid=(l+r)>>1; if(mid*sum[n]+maxn[n]>=x) { r=mid; ans=mid; } else l=mid+1; } printf("%lld ",(long long)(ans*n+(long long)(lower_bound(maxn+1,maxn+n+1,x-ans*sum[n])-maxn-1))); } puts(""); } return 0; } ```