Codeforces 1490G - Old Floppy Drive (二分、数学)

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


题意

给定一个包含 n n n个整数的数组 { a } \{a\} { a},可以循环延申至无穷个元素(定义编号 n n n的后一个元素为编号 1 1 1

再给定 m m m个询问 x x x,对于每个 x x x

问无穷数组 { a } \{a\} { a}前缀和数组 { S } \{S\} { S}中,第一次出现 S i ≥ x S_i\ge x Six的下标 i i i是多少(输出时下标要 − 1 -1 1

若不存在,输出 − 1 -1 1


限制

1 ≤ T ≤ 1 0 4 1\le T\le 10^4 1T104

1 ≤ n , m ≤ 2 ⋅ 1 0 5 1\le n,m\le 2\cdot 10^5 1n,m2105

− 1 0 9 ≤ a i ≤ 1 0 9 -10^9\le a_i\le 10^9 109ai109

1 ≤ x i ≤ 1 0 9 1\le x_i\le 10^9 1xi109

∑ n ≤ 2 ⋅ 1 0 5 ,   ∑ m ≤ 2 ⋅ 1 0 5 \sum n\le 2\cdot 10^5,\ \sum m\le 2\cdot 10^5 n2105, m2105




思路

注意求的是第一次出现 a i ≥ x a_i\ge x aix的下标 i i i,不是 a i = x a_i=x ai=x(读错题了,可惜)


S k = ∑ i = 1 k a i ,   M k = max ⁡ i = 1 k S i S_k=\sum_{i=1}^k a_i,\ M_k=\max_{i=1}^k S_i Sk=i=1kai, Mk=maxi=1kSi

根据 { M } \{M\} { M}的定义

如果 M n ≥ x M_n\ge x Mnx,说明答案存在于 1 1 1 n n n之间

又因为 { M } \{M\} { M}是非递减数组,所以可以通过二分查找来直接找到最小下标

否则,对 S n S_n Sn的正负性质进行讨论

  • 如果 S n ≤ 0 S_n\le 0 Sn0,又因为此时 M n < x M_n\lt x Mn<x,所以不存在任何一种状态满足 S i ≥ x S_i\ge x Six,故输出 − 1 -1 1
  • 如果 S n > 0 S_n\gt 0 Sn>0

根据题意, S i + n = S i + S n S_{i+n}=S_i+S_n Si+n=Si+Sn

定义 d = x − M n d=x-M_n d=xMn,表示询问的值与 1 1 1 n n n中所能得到最大的值的差值

于是发现,要想得到大于等于 x x x的数, 1 1 1 n n n中的最大值 M n M_n Mn还需要加上 ⌈ d S n ⌉ \lceil\frac d {S_n}\rceil Snd S n S_n Sn才行

据上述,得到 M n + ⌈ d S n ⌉ ∗ S n ≥ x M_n+\lceil\frac d {S_n}\rceil*S_n\ge x Mn+SndSnx

M n ≥ x − ⌈ d S n ⌉ ∗ S n M_n\ge x-\lceil\frac d {S_n}\rceil*S_n MnxSndSn

故让 x x x减去 ⌈ d S n ⌉ ∗ S n \lceil\frac d {S_n}\rceil*S_n SndSn后,便能通过二分查找来直接找到最小下标,最后将下标加上 ⌈ d S n ⌉ ∗ n \lceil\frac d {S_n}\rceil*n Sndn即为答案




代码

(202ms/2000ms)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll mx[200050];

void solve()
{
    
    
    int n,m;
    cin>>n>>m;
    
    ll s=0;
    for(int i=1;i<=n;i++)
    {
    
    
        ll d;
        cin>>d;
        s+=d;
        mx[i]=max(mx[i-1],s);
    }
    
    while(m--)
    {
    
    
        ll q;
        cin>>q;
        if(mx[n]>=q)
            cout<<(lower_bound(mx+1,mx+1+n,q)-mx)-1<<' ';
        else
        {
    
    
            if(s<=0)
                cout<<"-1 ";
            else
            {
    
    
                ll d=q-mx[n];
                ll tim=(d+s-1)/s;
                q-=tim*s;
                cout<<(lower_bound(mx+1,mx+1+n,q)-mx+tim*n)-1<<' ';
            }
        }
    }
    cout<<'\n';
}

int main()
{
    
    
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;cin>>T;while(T--)
        solve();
    return 0;
}

https://www.cnblogs.com/stelayuri/p/14408083.html

猜你喜欢

转载自blog.csdn.net/qq_36394234/article/details/113830619
old