补题记录G. Old Floppy Drive

G. Old Floppy Drive

题意:给你一个长度为n的数组a,求出其中的前缀和数组s,然后有m次询问,每次询问给出一个数x,问使得a中前len个数的和刚好不小于x的个数-1是多少。如果一轮完成不了,就接着下轮继续加。
例如:原数组为\([1, -3, 4]\)于是前缀和数组为\([1, -2, 2]\),假如询问的是1,直接输出0即可\((s[1] = 1)\)假如询问的是5,则发现一轮完成不了,于是多组继续加。
\(1 + (-3) + 4 + 1 + (-3) + 4 + 1 = 5\)所以输出6
方法:二分
首先对于每次询问有多种情况,我们分类来想
设前缀和数组中的最大值为maxn,切s[n]为T(即一个周期,因为我们发现最终数组会呈现出\([s_1, s_2, s_3...s_n, T + s_1, T + s_2, ...T + s_3, 2T + s_1, 2T + s_2...]\))
1、\(maxn < x \& T \le 0\) 容易得知这种情况下,是不可能到达目标的,所以直接输出-1
2、\(maxn < x \& T > 0\)
3、\(maxn \ge x \& T \le 0\)
4、\(maxn \ge x \& T > 0\)
其中的3,4为一类,我们先讲这个情况
对于这种情况,我们容易知道是不用进行第二轮的,第一轮内就能解决,于是就变成了在s数组中找到第一个大于等于x的数。我们用一个maxn数组来解决,\(max_s[i]\)表示前i个数中最大的数是多少,发现此时的max_s数组具有单调性,二分即可

int l = 1, r = n;
while (l < r) {
	int mid = (l + r) >> 1;
	if (max_s[mid] >= x) r = mid;
	else l = mid + 1;
}
cout << l - 1 << ' ';

其实第二类也差不多,我们发现如果要找一定要找周期最小的,那对于哪个数字来说可以用更小的周期到达数字呢?当然是最大的数了,所以我们最初先定下一个round,然后再用maxn数组进行二分验证即可

int round = (x - maxn + T - 1) / T;
int l = 1, r = n;
while (l < r) {
	int mid = (l + r) >> 1;
	if (round * T + max_s[mid] >= x) r = mid;
	else l = mid + 1;
}
cout << round * n + l - 1 << ' ';

加个预处理就行啦
友情提示:别忘了开long long

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 2e5 + 10;
inline int lc(int u) {return u << 1;}
inline int rc(int u) {return u << 1 | 1;}
inline int lowbit(int x) {return x & (-x);}
LL max_s[N], s[N];
inline void solve() {
    int n, m; cin >> n >> m;
    LL maxn = -1e9;
    max_s[0] = -1e9;
    for (int i = 1; i <= n; i ++ ) {
        int x; cin >> x;
        s[i] = s[i - 1] + x;
        maxn = max(maxn, s[i]);
        max_s[i] = max(max_s[i - 1], s[i]);
    }
    LL T = s[n];
    while (m -- ) {
        int x; cin >> x;
        if (maxn < x && T <= 0) cout << -1 << ' ';
        else {
            if (maxn >= x) {
                int l = 1, r = n;
                while (l < r) {
                    int mid = (l + r) >> 1;
                    if (max_s[mid] >= x) r = mid;
                    else l = mid + 1;
                }
                cout << l - 1 << ' ';
            } else {
                LL round = (x - maxn + T - 1) / T;
                int l = 1, r = n;
                while (l < r) {
                    int mid = (l + r) >> 1;
                    if (round * T + max_s[mid] >= x) r = mid;
                    else l = mid + 1;
                }
                cout << round * n + l - 1 << ' ';
            }
        }
    }
    cout << '\n';
}
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int t; cin >> t;
    while (t -- )
        solve();
    return 0;
}
posted @ 2021-04-29 17:41  Time_Limit_Exceeded  阅读(54)  评论(0编辑  收藏  举报