Разработайте систему стимулирования чтения электро...
تم الإنشاء في: ٣١ أكتوبر ٢٠٢٥
تمت الإجابة باستخدام GPT-5 Thinking بواسطة Chat01
تم الإنشاء في: ٣١ أكتوبر ٢٠٢٥
تمت الإجابة باستخدام GPT-5 Thinking بواسطة Chat01
Разработайте систему стимулирования чтения электронных книг. Для простоты будем считать, что книга всего одна, но её одновременно читают много людей. Нужно следить за прогрессом чтения у всех пользователей и выводить мотивирующие уведомления. А именно, программа должна обрабатывать следующие события:
READ user page — сохранить факт того, что пользователь под номером user дочитал книгу до страницы page. Если ранее такой пользователь не встречался, нужно его добавить. Гарантируется, что в рамках одного пользователя номера страниц в соответствующих ему событиях возрастают.
CHEER user — сообщить пользователю user, какая доля существующих пользователей, не считая его самого, прочитала меньшую часть книги, чем он. Если этот пользователь на данный момент единственный, доля считается равной 1. Если для данного пользователя пока не было ни одного события READ, доля считается равной 0, а сам пользователь не учитывается при вычислении долей для других пользователей до тех пор, пока для него не случится событие READ.
Формат входных данных
В первой строке вводится количество запросов Q — натуральное число, не превосходящее 10⁶. В следующих Q строках в соответствии с описанным выше форматом вводятся запросы. Гарантируется, что все вводимые числа целые и положительные, при этом номера пользователей не превосходят 10⁵, а номера страниц не превосходят 1000.
Пример ввода:
12
CHEER 5
READ 1 10
CHEER 1
READ 2 5
READ 3 7
CHEER 2
CHEER 3
READ 3 10
CHEER 3
READ 3 11
CHEER 3
CHEER 1
Формат выходных данных
Для каждого запроса CHEER user выведите единственное вещественное число от 0 до 1 — долю пользователей, прочитавших меньше страниц, чем user. Для вывода числа на экран используйте setprecision(6).
Пример вывода, соответствующий примеру ввода:
0
1
0
0.5
0.5
1
0.5
Пользователь 5 не учитывается при вычислении долей, потому что для него не произошло ни одного события READ. Пользователь 1 изначально был единственным, но в конце его обогнал третий, но не обогнал второй, поэтому он оказался продуктивнее 50% пользователей. Пользователь 3 изначально обгонял только второго и потому получал долю 50%, но в конце обогнал первого и получил долю 100%.
Ограничения
Четыре секунды на выполнение всех запросов. Все описанные в условии гарантии действительно справедливы для всех тестов, на которых будет запускаться ваша программа. Проверять корректность ввода не нужно. Гарантируется, что все вводимые числа целые и положительные. При этом номера пользователей не превосходят 10⁵, а номера страниц не превосходят 1000. Общее количество запросов не превосходит 10⁶. Храните два вектора. В первом по индексу n будет храниться номер страницы, до которой дочитал пользователь id, равным n. Во втором по каждому индексу m будет храниться количество пользователей, дочитавших как минимум до страницы m.
Ниже — простое и очень быстрое решение с двумя массивами, как просят в условии.
last_page[id] — до какой страницы дочитал пользователь id (0, если ещё не читал).ge[m] — сколько пользователей дочитали как минимум до страницы m.READ u p: пусть раньше было old = last_page[u]. Тогда для всех m от old+1 до p увеличиваем ge[m] на 1 и записываем last_page[u] = p.(#пользователей) * 1000, что укладывается в лимиты.CHEER u:
last_page[u] == 0 → ответ 0;active = ge[1].active == 1 → ответ 1;p = last_page[u], тогдаu: less = active - ge[p],less / (active - 1).READ: амортизированно O(Δp) с суммой Δp ≤ 1000 на пользователя → суммарно ≤ 1e8 простых инкрементов.CHEER: O(1).cpp#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); const int MAX_USER = 100000; const int MAX_PAGE = 1000; int Q; if (!(cin >> Q)) return 0; vector<int> last_page(MAX_USER + 1, 0); // last_page[id] vector<int> ge(MAX_PAGE + 2, 0); // ge[m] = count(read >= m) cout << setprecision(6); // как в условии (без fixed — как в примере) for (int qi = 0; qi < Q; ++qi) { string cmd; cin >> cmd; if (cmd == "READ") { int u, p; cin >> u >> p; int old = last_page[u]; if (p > old) { // теперь этот пользователь считается дочитавшим до всех m в [old+1, p] for (int m = old + 1; m <= p; ++m) { ++ge[m]; } last_page[u] = p; } } else if (cmd == "CHEER") { int u; cin >> u; if (last_page[u] == 0) { cout << 0 << '\n'; // ещё не читал continue; } int active = ge[1]; // все, кто прочитал >= 1 страницы if (active == 1) { cout << 1 << '\n'; // единственный активный читатель continue; } int p = last_page[u]; int less = active - ge[p]; // у кого строго меньше страниц double ans = static_cast<double>(less) / static_cast<double>(active - 1); cout << ans << '\n'; } } return 0; }
Эта программа полностью соответствует требованию «хранить два вектора» и проходит по времени при заданных ограничениях.