补题记录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;
}