Codeforces1490 G. Old Floppy Drive(二分)

题意:

在这里插入图片描

数据范围:1<=n,m<=2e5,-1e9<=a(i)<=1e9,1<=x<=1e9

解法:

令sum[]为a[]的前缀和,
ma[]为sum[]的前缀max.

(首先,观察到询问的x一定是>=1)
对于询问x,如果x已经被标记,那么可以直接返回答案.
1.如果sum[n]<=0,且x>ma[n],那么一定无解.
如果x<=ma[n],那么直接在ma[]上二分出一个最小的pos2,
满足ma[pos2]>=x即可.
2.如果sum[n]>0:
由于每一轮坐标一定是增大的,
二分出一个最小的pos,满足pos*sum[n]+ma[n]>=x,
然后再在ma[]上二分出一个最小的pos2,
满足ma[pos2]>=x-pos*sum[n]即可.

code:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxm=2e6+5;
int sum[maxm];
int ma[maxm];
int a[maxm];
int n,m;
int check(int mid,int x){
    
    
    return 1.0*mid*sum[n]+ma[n]>=x;//这里爆longlong呀
}
int getpos(int x){
    
    
    int l=0,r=1e9;
    int pos=-1;
    while(l<=r){
    
    
        int mid=(l+r)/2;
        if(check(mid,x))pos=mid,r=mid-1;
        else l=mid+1;
    }
    return pos;
}
int cal(int x){
    
    
    int pos=-1;
    if(sum[n]<=0){
    
    
        if(x>ma[n])return -1;
        else pos=0;
    }else{
    
    
        pos=getpos(x);
    }
    int t=x-pos*sum[n];
    int l=1,r=n;
    int pos2=-1;
    while(l<=r){
    
    
        int mid=(l+r)/2;
        if(ma[mid]>=t)pos2=mid,r=mid-1;
        else l=mid+1;
    }
    return pos*n+pos2;
}
void solve(){
    
    
    cin>>n>>m;
    for(int i=1;i<=n;i++){
    
    
        cin>>a[i];
    }
    ma[0]=-1e18;
    sum[0]=0;
    for(int i=1;i<=n;i++){
    
    
        sum[i]=sum[i-1]+a[i];
        ma[i]=max(ma[i-1],sum[i]);
    }
    while(m--){
    
    
        int x;cin>>x;
        int ans=cal(x);
        if(ans!=-1)ans--;
        cout<<ans<<' ';
    }
    cout<<endl;
}
signed main(){
    
    
    ios::sync_with_stdio(0);
    int T;cin>>T;
    while(T--){
    
    
        solve();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/114006809