Codeforces G. Old Floppy Drive(二分+数学)

题目链接


题目大意: 给你 n n n个数,对其m次询问,问第一个前缀大于等于x的下标(从0开始),(n-1)后跟的是第0个元素,就是周期性.下标不是周期性.


思路:
先看如果当前要查询的x比第一个周期中最大的小,那么一定能在第一个周期中找到.我们想让他很开得查到下标,但是前缀和的话不一定满足单调性.

所以我们可以尝试将其转化成有单掉性的序列,也能用到前缀和,那么我们就可以维护当前前缀和最大数值也就是 S k = ∑ k i = 1 x ; M k = m a x i = 1 k S i ; S_{k}=\sum_{k}^{i=1}{x}; M_{k}=max_{i=1}^{k}S_{i}; Sk=ki=1x;Mk=maxi=1kSi; 这样我们就可以直接用M数组二分查询大于等于x的第一个前缀下标.

其次如果我们前面定义的S(n)<=0那么就不会出一个周期,因为出了一个周期那么那就会一直减小.所以就没有结果.(-1);

如果大于0的话,就说明我们需要走过至少一个周期,那么我们先减去一个周期的最大值,再看看最少走多少个周期(上取整).最后再二分出除去这么多周期剩下的.将下标加起来.

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=998244353;
const int MOD=10007;

inline int read() {
    
    
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}

/*
vector<ll> m1;
vector<ll> m2;
priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆 		小到大
priority_queue<ll , vector<ll> , less<ll> > mx;//下   	大根堆  	大到小
*/
map<ll,ll>mp;
map<ll,ll>mpp;
ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],cc[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;

#define read read()
int main() {
    
    
    cin>>t;
    while(t--) {
    
    
        cin>>n>>m;
        sum=0;
        for(int i=1; i<=n; i++) {
    
    
            scanf("%lld",&p);
            sum=sum+p;
            a[i]=max(a[i-1],sum);
        }
        while(m--) {
    
    
            cin>>l;
            if(l<=a[n]) {
    
    
                cout<<((lower_bound(a+1,a+1+n,l)-a)-1)<<" ";
            } else {
    
    
                if(sum<=0) {
    
    
                    cout<<"-1 ";
                } else {
    
    
                    cnt=l-a[n];
                    ans=(cnt+sum-1)/sum;
                    l-=ans*sum;
                    cout<<(lower_bound(a+1,a+1+n,l)-a)-1+ans*n<<" ";
                }
            }
        }
        cout<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45911397/article/details/114803706
今日推荐