Official
F - 累計数/Cumulative Number Editorial
by
F - 累計数/Cumulative Number Editorial
by
sheyasutaka
各日の累計枚数 \(A'_i := A_1 + \dots + A_i\) を先頭から順に求めておきます。
このとき各クエリに対して、\(x \leq A'_k\) を満たす最小の \(k\) を求めればよいです(\(x > A'_N\) の場合は存在しないので \(-1\))。
\(A'_k\) は単調増加なので、答えとなる \(k_{ans}\) について以下の \(2\) つが成り立ちます。
- \(k < k_{ans}\) ならば、\(x \leq A'_k\) は満たされない。
- \(k \leq k_{ans}\) ならば、\(x \leq A'_k\) は満たされる。
この単調性より、二分探索によって \(k_{ans}\) を求めることができます。時間計算量は前処理 \(O(N)\)、クエリごとに \(O(\log N)\) です。
実装例 (C++)
#include <iostream>
#include <cstdio>
#include <vector>
using std::cin;
using std::cout;
using std::cerr;
using std::endl;
using std::pair;
using std::make_pair;
using std::vector;
using std::min;
using std::max;
typedef long long int ll;
ll n, q;
vector<ll> a, x;
void solve () {
vector<ll> accum(n+1, 0LL);
for (ll i = 0; i < n; i++) {
accum[i+1] = accum[i] + a[i];
}
for (ll i = 0; i < q; i++) {
ll ok = n+1, ng = 0;
while (ng + 1 < ok) {
ll med = (ok + ng) / 2;
if (accum[med] >= x[i]) {
ok = med;
} else {
ng = med;
}
}
if (ok == n+1) {
cout << "-1" << "\n";
} else {
cout << ok << "\n";
}
}
return;
}
int main (void) {
std::ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
a.resize(n);
for (ll i = 0; i < n; i++) {
cin >> a[i];
}
cin >> q;
x.resize(q);
for (ll i = 0; i < q; i++) {
cin >> x[i];
}
solve();
return 0;
}
