A. Printer
#include <bits/stdc++.h>
using i64 = long long;
void Solve() {
int n, K;
std::cin >> n >> K;
std::vector<int> t(n), l(n), w(n);
for (int i = 0; i < n; ++i) {
std::cin >> t[i] >> l[i] >> w[i];
}
auto check = [&](i64 mid) -> bool {
i64 ans = 0;
for (int i = 0; i < n; ++i) {
i64 T = 1LL * t[i] * l[i] + w[i];
ans += mid / T * l[i];
ans += std::min((mid % T) / t[i], 1LL * l[i]);
if (ans >= K) {
return true;
}
}
return false;
};
i64 lo = 0, hi = 2e18;
while (lo < hi) {
i64 mid = (lo + hi) / 2;
if (check(mid)) {
hi = mid;
} else {
lo = mid + 1;
}
}
std::cout << lo << '\n';
}
int main() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
for (int ti = 1; ti <= t; ++ti) {
// std::cerr << "Solve : " << ti << '\n';
Solve();
}
return 0;
}
C. Colorful Segments 2
#include <bits/stdc++.h>
using i64 = long long;
constexpr int P = 998244353;
void Solve() {
int n, K;
std::cin >> n >> K;
std::map<int, std::array<int, 2>> f;
i64 ans = 1;
for (int i = 0; i < n; ++i) {
int l, r;
std::cin >> l >> r;
f[l][0]++;
f[r + 1][1]++;
}
for (auto [_, v] : f) {
for (int i = 0; i < v[1]; ++i) {
K++;
}
for (int i = 0; i < v[0]; ++i) {
ans = ans * std::max(0, K) % P;
K--;
}
}
std::cout << ans << '\n';
}
int main() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
for (int ti = 1; ti <= t; ++ti) {
// std::cerr << "Solve : " << ti << '\n';
Solve();
}
return 0;
}
D. Hero of the Kingdom
设这次交易能获得
k
∗
(
q
−
p
)
k*(q-p)
k∗(q−p) 的利润,我们对每一种
k
k
k一起处理,复杂度
O
(
1
)
O(1)
O(1),
而不同的
k
k
k总共有不到
t
\sqrt{t}
t 种,故复杂度为
O
(
t
)
O(\sqrt{t})
O(t)
#include <bits/stdc++.h>
using i64 = long long;
void Solve() {
i64 p, a, b, q, c, d, m, t;
std::cin >> p >> a >> b >> q >> c >> d >> m >> t;
while (true) {
i64 buy = m / p;
if (buy <= 0) {
break;
}
i64 time = a * buy + b + c * buy + d;
// increase coins
i64 inc = (q - p) * buy;
i64 lev = (buy + 1) * p;
i64 round = (lev - m + inc - 1) / inc;
i64 totime = time * round;
if (t >= totime) {
t -= totime;
m += round * inc;
} else {
i64 k = t / time;
m += k * inc;
t %= time;
t -= (b + d);
if (t <= 0) {
break;
}
m += t / (a + c) * (q - p);
break;
}
}
std::cout << m << '\n';
}
int main() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
for (int ti = 1; ti <= t; ++ti) {
// std::cerr << "Solve : " << ti << '\n';
Solve();
}
return 0;
}
E.Sensors
思考一个问题:如果询问改成离线,应该怎么做?
我们需要查询每个区间最晚的和第二晚变色的球,运用线段树即可做到
O
(
l
o
g
(
n
)
)
O(log(n))
O(log(n))查询
本题为强制在线,需要另辟蹊径。
观察到区间为一开始给定,我们把 [ l , r ] [l,r] [l,r]这个区间下放到线段树上,把 [ l , r ] [l,r] [l,r]划分为 k k k个子区间: [ l 1 , r 1 ] , [ l 2 , r 2 ] . . . [ l k , r k ] [l_1,r_1],[l_2,r_2]...[l_k,r_k] [l1,r1],[l2,r2]...[lk,rk],而 k ≤ 2 ∗ l o g ( n ) k\le2*log(n) k≤2∗log(n),并将这 k k k个子区间打上标记。
接下来进行到修改操作,注意到一次修改影响到最多 l o g ( n ) log(n) log(n)个子区间
对于每个子区间,我们记
c
n
t
cnt
cnt为子区间剩余红球数量,在变色修改时更新
c
n
t
cnt
cnt
在
c
n
t
<
2
cnt<2
cnt<2的时候,我们需要传递信息给所有的标记区间,
如果标记区间剩下恰好一个红球,则计入答案(这部分看代码会更方便理解)
由于每个子区间传递次数不超过两次,而子区间总数 < 4 n <4n <4n,故时间复杂度为 O ( n ∗ l o g ( n ) ) O(n*log(n)) O(n∗log(n))
#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 5e5 + 5;
int n, m;
int L[N], R[N];
int cnt[N * 4];
int res[N];
std::vector<int> Q[N * 4]; // Interval id
#define lc (p << 1)
#define rc (p << 1 | 1)
#define mid ((l + r) >> 1)
#define lson lc, l, mid
#define rson rc, mid + 1, r
void build(int p, int l, int r) {
cnt[p] = r - l + 1; // less than 2
Q[p].clear();
if (l == r) {
return;
}
build(lson);
build(rson);
}
void modify(int p, int l, int r, int x) {
if (R[x] < l || r < L[x]) return;
if (L[x] <= l && r <= R[x]) {
if (l == r) {
res[x] += 1;
} else {
res[x] += 2;
}
Q[p].push_back(x);
return;
}
modify(lson, x);
modify(rson, x);
}
i64 ans;
void update(int p, int l, int r, int x) {
--cnt[p];
if (cnt[p] < 2) {
for (auto i : Q[p]) {
--res[i];
if (res[i] == 1) {
ans += 1LL * i * i;
}
if (res[i] == 0) {
ans -= 1LL * i * i;
}
}
}
if (l == r) return;
if (x <= mid) {
update(lson, x);
} else {
update(rson, x);
}
}
void Solve() {
std::cin >> n >> m;
build(1, 0, n - 1);
ans = 0;
for (int i = 1; i <= m; ++i) {
res[i] = 0;
std::cin >> L[i] >> R[i];
modify(1, 0, n - 1, i);
if (res[i] == 1) {
ans += 1LL * i * i;
}
}
std::cout << ans << ' ';
for (int i = 0; i < n; ++i) {
int x;
std::cin >> x;
x = (x + ans) % n;
// std::cerr << "query : " << x << '\n';
update(1, 0, n - 1, x);
std::cout << ans << ' ';
}
std::cout << '\n';
}
int main() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
for (int ti = 1; ti <= t; ++ti) {
// std::cerr << "Solve : " << ti << '\n';
Solve();
}
return 0;
}
F.Divide the Sequence
#include <bits/stdc++.h>
using i64 = long long;
void Solve() {
int n;
std::cin >> n;
std::vector<i64> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
std::reverse(a.begin(), a.end());
for (int i = 1; i < n; ++i) a[i] += a[i - 1];
std::sort(a.begin(), a.end() - 1);
std::reverse(a.begin(), a.end());
for (int i = 1; i < n; ++i) a[i] += a[i - 1];
for (int i = 0; i < n; ++i) {
std::cout << a[i] << " \n"[i == n - 1];
}
}
int main() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
for (int ti = 1; ti <= t; ++ti) {
// std::cerr << "Solve : " << ti << '\n';
Solve();
}
return 0;
}