[Codeforces 1490G]Old Floppy Drive

文章中若有不严谨或错误的地方,欢迎在评论中指出QAQ

Description

题目链接

给出长度为 \(n\) 的数组 \(a\),第 \(0\) 秒从 \(a_1\)开始,此时总和为 \(a_i\),每过一秒就总和加上下一个 \(a_i\),若加到 \(a_n\),那么下一秒将会从 \(a_1\) 开始加,给出 \(m\) 个询问,每个询问包含一个

\(x_i\),问第一次总和大于等于 \(x_i\) 时是在第几秒。

\(1 \le n, m \le 2 \cdot 10^5\) , \(-10^9 \le a_i \le 10^9\) , \(1 \le x \le 10^9\)

Solution

由题目,很容易想到用前缀和来做,然后将 \(x_i\) 处理一下,再二分到第一个大于等于 \(x_i\) 的位置,所以关键就是如何将前缀和变成有序的。

考虑题目问的是第一次大于等于的位置,所以若当前 \(a_i\) 是负的,那么若当前位置满足条件,其前面也一定满足条件,并且位置靠前。

所以当 \(a_i\) 为负数时,可以不用考虑其前缀和,也就是说若当前前缀和小于前一个前缀和,取前一个前缀和即可。

然后前缀和数组就变成严格递增的序列了,之后用二分找到满足条件的位置就行。

Code

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 2e5+10;

int a[N];
ll sum[N];
ll mx[N];

int main()
{
    int t;
    cin >> t;
    while(t -- )
    {
        int n,m;
        cin >> n >> m;
        for (int i = 1 ; i <= n ; i ++ ) cin >> a[i];
        for (int i = 1 ; i <= n ; i ++ )
        {
            sum[i] = a[i] + sum[i-1];
            mx[i] = max(mx[i-1],sum[i]);
        }
        while(m -- )
        {
            ll x;
            cin >> x;
            auto it = lower_bound(mx+1,mx+1+n,x) - mx;
            if(it <= n){
                cout << it-1 << ' ';
                continue;
            }
            if(sum[n] <= 0){
                cout << -1 << ' ';
                continue;
            }
            ll ans = (x - mx[n] - 1) / sum[n] + 1;
            x -= ans * sum[n];
            it = lower_bound(mx+1,mx+1+n,x) - mx;
            cout << it + ans * n - 1 << ' ';
        }
        cout << endl;
    }
    return 0;
}
上一篇:vim 命令 ,操作,快捷键 记录


下一篇:Linux内核源码分析 -- 更新当前进程的 cred -- commit_creds