s[j]表示前缀和,S = s[n]
若S为负数,对所有输入数据取相反数,从而使得S为正。(若存在重复前缀,仅保留靠左的)这样只需要找到与x同余的前缀中最大的那个数,同时保证sj <= x
!!!数组判越界,输出看long long
!!!数组判越界,输出看long long
!!!数组判越界,输出看long long
code:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
unordered_map<int, int> ex, loc;
int n, m;
int idx = 1;
int Get(int x) {
if (!ex[x]) ex[x] = idx++;
return ex[x];
}
int t, T;
int ask[N], a[N];
int p[N];
vector<int> v[N];
int Bsearch(int id, int x) { // 找与x同余的数中第一个小于等于x的数
//无解
if (id >= N) return -1 ;
if (v[id].empty())return -1;
if (v[id][0] > x) return -1;
//有解
int l = 0, r = v[id].size() - 1;
while (l + 1 < r) {
int mid = (l + r) >> 1;
if (v[id][mid] <= x) l = mid;
else r = mid;
}
if (v[id][r] <= x) return loc[v[id][r]] + ((x - v[id][r]) / T) * n;
else if (v[id][l] <= x) return loc[v[id][l]] + ((x - v[id][l]) / T) * n;
}
void solve1() {
for (int i = 1; i <= n; i++) {
p[i] = p[i - 1] + a[i];
if (!loc[p[i]]) loc[p[i]] = i;
}
for (int i = 1; i <= m; i++) {
if(ask[i] == 0) printf("0\n");
else if (loc[ask[i]]) printf("%lld\n", loc[ask[i]]);
else printf("-1\n");
}
}
void solve2() {
for (int i = 1; i <= n; i++) {
p[i] = p[i - 1] + a[i];
if (!loc[p[i]]) {
loc[p[i]] = i;
int id = Get((p[i] % T + T) % T);
v[id].push_back(p[i]);
}
}
for (int i = 0; i <=idx; i++) {
sort(v[i].begin(), v[i].end());
}
for (int i = 1; i <= m; i++) {
if(ask[i] == 0) printf("0\n");
else{
int id = Get((ask[i] % T + T) % T);
printf("%lld\n", Bsearch(id, ask[i]));
}
}
}
signed main() {
//freopen("in", "r", stdin);
cin >> t;
while (t--) {
ex.clear();
loc.clear();
idx = 1;
T = 0;
cin >> n >> m;
for (int i = 0; i <= n; i++) p[i] = 0 , v[i].clear() ;
for (int i = 1; i <= n; i++) cin >> a[i], T = T + a[i];
for (int i = 1; i <= m; i++) cin >> ask[i];
if (T == 0) {
solve1();
} else if (T < 0) {
T = -T;
for (int i = 1; i <= n; i++) a[i] = -a[i];
for (int i = 1; i <= m; i++) ask[i] = -ask[i];
solve2();
} else {
solve2();
}
}
return 0;
}