Реши задачу на c++. Вам надоело заниматься олимпиа...

Создано: 16 августа 2025 г.

Отвечено с использованием GPT-5 Thinking от Chat01

Вопрос

Реши задачу на c++.
Вам надоело заниматься олимпиадным программированием, поэтому было решено посвятить
оставшуюся часть жизни работе в саду.
Есть n яблонь, пронумерованных от 1 до n. Изначально (день 0) на деревьях ничего нет. Каждый
день на i-й яблоне вырастает i яблок.
Вы q раз хотите собрать урожай — в di-й день будут собраны все яблоки с деревьев на отрезке
[li
, ri
].
Вам стало интересно, а сколько денег вы сможете заработать на продаже фруктов. Для этого
после каждого сбора урожая нужно знать, сколько яблок вы собрали.
Формат входных данных
В первой строке дано число n (1 <= n <= 10^18) — количество яблонь.
На второй строке находится число q (1 <= q <= 2 · 10^5
) — количество раз, которое вы соберете
урожай.
Следующие q строк описывают сборы урожая. В i-й из них даны числа di
, li
, ri (1 <= li <= ri <= n,
1 <= di <= 10^18).
Гарантируется, что последовательность di возрастает.
Формат выходных данных
Выведите q строк. В i-й из них сообщите, сколько яблок будет собрано во время i-го сбора урожая
по модулю 998244353.

Мысль

Understanding the problem

Okay, so we have n apple trees, numbered 1 to n. Every day, tree i grows i apples, meaning the apples accumulate until they are harvested. Given q harvest events, I need to check how many apples have gathered on each tree between harvests and calculate the total harvested apples for each event.

Clarifying harvest logic

So, on day d_i, all apples from trees in the range [l_i, r_i] are harvested. The apples on each tree grow every day until the harvest. The formula would be the difference in days between the current and the last harvest, multiplied by the tree’s number, summed over the range of trees being harvested.

Breaking down the data structure

We need to manage an array lastDay for each tree. After a harvest, we need a way to efficiently update the last harvest day for a range of trees and query the total apples across a range of trees. A segment tree with lazy propagation will allow us to do range sum and range assignments efficiently, even if the number of trees is large.

Efficient range operations

To quickly compute the sum of indices [l, r], I'll use the formula sum(j) = (l + r) * (r - l + 1) / 2. For the lastDay[j] * j sums, we can use an ordered map to manage intervals with the same lastDay. Each harvest operation splits intervals and calculates the sum within the range, updating segments as needed. This structure allows handling up to 200,000 operations efficiently.

Handling large values with modular arithmetic

The task involves managing large numbers and applying modular arithmetic (mod 998244353) due to the possible size of n (up to 1e18) and d. We will compute sums over ranges, carefully applying mod operations to avoid overflow, and use efficient data structures like ordered maps for interval management. Each operation will split and adjust segments, ensuring every calculation remains manageable within modular constraints.

Optimizing segment operations

The approach involves handling very large numbers with modular arithmetic, safely calculating sums over potentially huge ranges. We aim to minimize processing with efficient segment management, using interval unions and splits to prevent excessive recomputation. Each query complexity is kept manageable through amortization, with careful attention to possible edge cases, such as handling large values and varying segment splitting. By strategically limiting segment operations, the solution ensures scalability.

Optimizing segment handling

The goal is to handle the range assignments efficiently by splitting and merging segments while managing large numbers with modular arithmetic. Each query involves splitting and updating intervals, with optimized O(q log q) complexity. I’m focusing on ensuring type safety with 64-bit integers and minimizing unnecessary merges to keep the code simpler. All operations handle large inputs effectively, respecting boundary conditions and ensuring correctness while avoiding edge cases.

Thought for 1m 51s

Ответ

в этой задаче у каждого дерева jj хранится день последнего сбора last[j]last[j] (изначально 0).
Если в день dd собираем на отрезке [l,r][l,r], то урожай равен

j=lr(dlast[j])j=dj=lrj    j=lrlast[j]j.\sum_{j=l}^{r} (d-last[j])\cdot j = d\cdot \sum_{j=l}^{r} j\;-\;\sum_{j=l}^{r} last[j]\cdot j .

Первое слагаемое считаем формулой суммы арифм. прогрессии, второе — если поддерживать разбиение [1..n][1..n] на непересекающиеся отрезки с одинаковым значением lastlast. Тогда каждый запрос: «разбить» карту в точках ll и r+1r+1, пробежать отрезки внутри [l,r][l,r], посчитать вклад, стереть их и записать новый отрезок [l,r][l,r] со значением dd. Амортизированно это O(klogm)O(k\log m) на запрос, где kk — число затронутых отрезков (в сумме O(qlogq)O(q\log q)).

Ниже — аккуратная реализация на C++ с 64-битными числами и модулем 998244353998244353.

cpp
#include <bits/stdc++.h> using namespace std; using int64 = long long; const long long MOD = 998244353; const long long INV2 = (MOD + 1) / 2; // 2^{-1} mod MOD struct Node { long long r; // right boundary of segment long long val; // last harvest day for this segment }; inline long long addmod(long long a, long long b) { long long s = a + b; if (s >= MOD) s -= MOD; return s; } inline long long submod(long long a, long long b) { long long s = a - b; if (s < 0) s += MOD; return s; } inline long long mulmod(long long a, long long b) { return (long long)((__int128)a * b % MOD); } // T(x) = 1 + 2 + ... + x (mod MOD) inline long long tri(unsigned long long x) { unsigned long long xm = x % MOD; unsigned long long xp1 = (x + 1) % MOD; return mulmod((long long)xm, mulmod((long long)xp1, (long long)INV2)); } // S(l,r) = l + ... + r (mod MOD) inline long long sum_j(unsigned long long l, unsigned long long r) { return submod(tri(r), tri(l - 1)); } // interval map: key = left boundary; value = {right, lastDay} map<long long, Node> seg; // split at position pos; returns iterator to segment starting at pos, // or seg.end() if pos == n+1 (i.e., after the last position) auto split(long long pos) { if (seg.empty()) return seg.end(); auto it = seg.upper_bound(pos); if (it == seg.begin()) return seg.begin(); // pos <= first L (shouldn't happen for pos>=1) --it; long long L = it->first, R = it->second.r, V = it->second.val; if (pos > R) return seg.end(); // pos is after this segment (e.g., n+1) if (pos == L) return it; // already starts here // split [L,R] into [L,pos-1] and [pos,R] it->second.r = pos - 1; return seg.emplace(pos, Node{R, V}).first; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); long long n; int q; if (!(cin >> n)) return 0; cin >> q; // initially whole [1..n] has lastDay = 0 seg[1] = Node{n, 0}; for (int i = 0; i < q; ++i) { long long d, l, r; cin >> d >> l >> r; long long dmod = d % MOD; auto itl = split(l); auto itr = split(r + 1); long long prevSum = 0; // sum of lastDay * j over [l,r] for (auto it = itl; it != itr; ++it) { long long L = it->first; long long R = it->second.r; long long last = it->second.val % MOD; long long s = sum_j((unsigned long long)L, (unsigned long long)R); prevSum = addmod(prevSum, mulmod(last, s)); } long long totalJ = sum_j((unsigned long long)l, (unsigned long long)r); long long ans = submod(mulmod(dmod, totalJ), prevSum); cout << ans << '\n'; // assign [l,r] := d seg.erase(itl, itr); seg[l] = Node{r, d}; // (optional) light merging with neighbors having the same value d // to keep the map small; not required for correctness. auto itNew = seg.find(l); // merge with previous if (itNew != seg.begin()) { auto itPrev = itNew; --itPrev; if (itPrev->second.r + 1 == itNew->first && itPrev->second.val == itNew->second.val) { itPrev->second.r = itNew->second.r; seg.erase(itNew); itNew = itPrev; } } // merge with next auto itNext = next(itNew); if (itNext != seg.end()) { if (itNew->second.r + 1 == itNext->first && itNext->second.val == itNew->second.val) { itNew->second.r = itNext->second.r; seg.erase(itNext); } } } return 0; }

Идеи ключевые

  • Держим «разбиение на отрезки с одинаковым последним днём сбора».
  • Ответ = djd \cdot \sum j минус (lastj)\sum (\text{last}\cdot j) по всем частям внутри [l,r][l,r].
  • Все суммы считаются по модулю через треугольные числа T(x)=x(x+1)/2T(x)=x(x+1)/2.
  • Амортизированная сложность O(qlogq)O(q \log q).

Поделиться этим Q&A