题意:圆盘上有 n 个数,起初指针在第一个位置,m 次询问,每次询问回答指针至少移动多少次使得指针所经过的所有数的和 >= x(指针不可反向)
思路:
维护一个递增的前缀和 b[ ],并记录达到该前缀和的位置 id[ ]。
(1)判断是否存在,若x > 前缀和的最大值且整个数组的和 <= 0,则不存在。
(2)如果第一轮就可以找到 >= x 的数,直接lower_bound;如果需要 k 轮,并且最后加的一个数为b[i],即求一对 i,k 满足 k * sum + b[i] >= x,且使 id[i] - 1 + k * n最小,显然应该先让k取最小,就是用最大的 b[i] 来求最小的 k ,所以
,tot为严格递增的前缀和的个数,再lower_bound即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 2e5 + 7;
ll a[N], b[N], id[N];
int main() {
ll t, n, m, x;
scanf("%lld", &t);
while(t--) {
scanf("%lld%lld", &n, &m);
ll sum = 0, maxx = 0, tot = 0;
b[0] = 0;
for(ll i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
sum += a[i];
maxx = max(maxx, sum);
if(sum > b[tot]) b[++tot] = sum, id[tot] = i;
}
for(ll i = 1; i <= m; ++i) {
scanf("%lld", &x);
if(i > 1) printf(" ");
if(x > maxx && sum <= 0) {
printf("-1");
continue;
}
if(x <= a[1]) {
printf("0");
continue;
}
if(x > maxx) {
ll cnt = (x - b[tot] + sum - 1) / sum;
ll it = lower_bound(b + 1, b + tot + 1, x - cnt * sum) - b;
printf("%lld", n * cnt + id[it] - 1);
}
else {
ll it = lower_bound(b + 1, b + tot + 1, x) - b;
printf("%lld", id[it] - 1);
}
}
printf("\n");
}
return 0;
}