Codeforces Round #702 (Div. 3) G. Old Floppy Drive

题意
给了n个数字,成一个环,最开始在第一个数字的位置上,每次移动就是向下移动一格。
m次询问,每次询问给出一个x,求最少要移动多少次,经过的数值之和≥x?

思路
询问次数,显然,每次询问需要一个log的做法。
我们维护一个前缀和sum,维护一个前缀和的最大值ma.
对于x,如果小于等于ma[n],也就是不用完整移动一轮就能找到答案,容易知道ma是单调不降的,可以二分快速找到。
对于剩下的,就说明ma[n]<x,那么我们要看每经过一轮大小会不会增加,因为x是正的。
如果sum[n]<=0,经过一轮不会增加,说明永远无法到达,输出-1。
否则我们就是要求一个最小的k,使得k * sum[n] + sum[o] >= x
那么答案就是k * n+ o
我们要让答案尽可能小,那么肯定要最小化k,所以这里的sum[o]取最大,其实也就是ma[n]。
那么要经过完成的跑完次数就是 ( x-ma[n] ) / sum[n] 这里要向上取整
所以就是 ( x-ma[n]-1 ) / sum[n] +1
对于o的位置 我们二分找到第一个出现的位置即可。


#include<bits/stdc++.h>
using namespace std;
const int N=3e5;
typedef long long ll;
ll sum[N],ma[N];
int main(){
    
    
    ma[0]=-2e9;
    int T;cin>>T;
    while(T--){
    
    
        int n,m;cin>>n>>m;
        for(int i=1;i<=n;i++){
    
    
            int x;cin>>x;
            sum[i]=sum[i-1]+x;
            ma[i]=max(ma[i-1],sum[i]);
        }
        while(m--){
    
    
            int x;cin>>x;
            if(ma[n]>=x){
    
    
                int ans=lower_bound(ma+1,ma+n+1,x)-ma;
                cout<<ans-1<<" ";
            }
            else{
    
    
                if(sum[n]<=0) cout<<-1<<" ";
                else{
    
    
                    ll cnt=(x-ma[n]-1)/sum[n]+1;
                    x-=cnt*sum[n];
                    int pos=lower_bound(ma+1,ma+n+1,x)-ma;
                    cout<<cnt*n+pos-1<<" ";

                }
            }
        }
        cout<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43563669/article/details/113851969
今日推荐