首先二分求出每个人结束的时间 $end_i$。
我们只需要求出每个人最后一次检票开始之后有多少次检票。即有多少个 $end_j-k\cdot a_j$ 大于等于 $end_i-a_i$,如果 $j\le i$ 则不能取等。
因为 $a_i$ 互不相同,且 $\max\{end_i\}-\min\{end_i-a_i\}\le 2C$ ($C=\max\{a_i\}$),因此有用的数的个数只有 $O(C\log k)$。
我们记录每个数的出现次数,求后缀和求能得到所有 $\ge end_i-a_i$ 的数的个数。再减去 $i$ 之前出现的等于 $end_i-a_i$ 的数的个数即可。
时间复杂度 $O(k\log nC+C\log k)$。
#include <bits/stdc++.h>
constexpr int N = 1e5;
int64_t n;
int k;
int a[N];
int64_t pos[N];
int cnt[2 * N], ans[N];
int64_t count(int64_t m) {
int64_t s = 0;
for (int i = 0; i < k; ++i)
s = std::min<int64_t>(s + (m + a[i] - 1) / a[i], 1e18);
return s;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin >> n >> k;
for (int i = 0; i < k; ++i)
std::cin >> a[i];
int64_t l = 0, r = 2e18;
while (l < r) {
int64_t m = (l + r + 1) / 2;
if (count(m) <= n) {
l = m;
} else {
r = m - 1;
}
}
int res = n - count(l);
for (int i = 0; i < k; ++i) {
pos[i] = (l + a[i] - 1) / a[i] * a[i];
if (pos[i] == l && res > 0) {
--res;
pos[i] += a[i];
}
}
int64_t mn = 2e18, mx = 0;
for (int i = 0; i < k; ++i) {
mx = std::max(mx, pos[i]);
mn = std::min(mn, pos[i] - a[i]);
}
for (int i = 0; i < k; ++i) {
for (int64_t j = pos[i] - a[i]; j >= mn; j -= a[i])
++cnt[j - mn];
ans[i] = -cnt[pos[i] - a[i] - mn];
}
for (int i = mx - mn - 2; i >= 0; --i)
cnt[i] += cnt[i + 1];
for (int i = 0; i < k; ++i) {
ans[i] += cnt[pos[i] - a[i] - mn];
std::cout << n - ans[i] << " \n"[i == k - 1];
}
return 0;
}