Разбор задач [contest: 417995]
[problem:417995A]
Автор задачи: Ilya_Is2022
Решение: Ilya_Is2022
В данной задаче требовалось вывести любое целое четное и одновременно простое число, лежащее на промежутке от $$$0$$$ до $$$n$$$. После не долгих размышлений, не сложно понять, что такое число только одно, а именно: $$$2$$$.
Асимптотика решения: $$$\mathcal{O}(1)$$$
n = int(input())
print(2)
[problem:417995B]
Автор задачи: Ilya_Is2022
Решение: Ilya_Is2022
Ожидается...
Ожидается...
[problem:417995C]
В этой задаче необходимо было использовать расширенный алгоритм Евклида для нахождения ответа.
Будем считать, что $$$c > 0$$$. Если $$$c = 0$$$, то можно вывести любое число (так как гарантируется, что ответ всегда существует). Иначе, если $$$c < 0$$$, то его можно сделать положительным, взяв математический остаток от деления на $$$m$$$.
Составим диофантово уравнение $$$cx + my = (b_i - d)$$$. Тогда можно заметить, что $$$a_i = x\ \%\ m$$$. Само число $$$x$$$, как уже было сказано, можно найти с помощью расширенного алгоритма Евклида за $$$\mathcal{O}(\log \max(c, m))$$$.
Можно заметить, что достаточно один раз найти решение уравнения $$$cx + my = \gcd(c, m)$$$. Пусть это решение равно $$$(x_0; y_0)$$$, тогда для $$$i$$$-го числа ответом является $$$x_0 \times \frac{b_i - d}{\gcd(c, m)}$$$ (Возможно, придётся взять остаток от деления на $$$m$$$)
Асимптотика решения: $$$\mathcal{O}(n + \log \max(c, m))$$$.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct g_res {
ll d, x, y;
};
ll mm(ll a, ll m) {
return (a % m + m) % m;
}
g_res gcd_ext(ll a, ll b) {
if (b == 0) {
return {a, 1, 0};
}
g_res g = gcd_ext(b, a % b);
return {g.d, g.y, g.x - g.y * (a / b)};
}
void solve() {
ll n, c, d, m, bi;
cin >> n >> c >> d >> m;
c = mm(c, m);
d = mm(d, m);
if (c == 0) {
for (ll i = 0; i < n; ++i) {
cout << "0";
if (i != n - 1) {
cout << " ";
}
}
cout << "\n";
return;
}
g_res g = gcd_ext(c, m);
for (int i = 0; i < n; ++i) {
cin >> bi;
cout << mm(mm(bi - d, m) / g.d * g.x, m);
if (i != n - 1) {
cout << " ";
}
}
cout << "\n";
}
int main() {
#ifndef NEKSTAS
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
#endif
int t = 1;
// cin >> t;
for (int i = 0; i < t; ++i) {
solve();
}
}
[problem:417995D]
Можно заметить, что пожелание каждого друга Алексея представляется в виде битовой маски длины $$$30$$$, где $$$i$$$-й справа бит равен $$$1$$$, если друг хочет подарок $$$i$$$-го вида и $$$0$$$ — если не хочет.
Тогда задача сводится к нахождению побитового ИЛИ всех чисел на отрезке массива от $$$l$$$ до $$$r$$$.
Её можно решать разными способами.
Например, можно посчитать для каждого бита по отдельности префиксные суммы (к текущей префиксной сумме прибавляется $$$1$$$, если $$$j$$$-й бит равен $$$1$$$) и тогда $$$j$$$-й бит в ответе на запрос равен $$$1$$$, если количество единичных битов на отрезке больше нуля ($$$p_{r,j} - p_{l-1,j} > 0$$$). Асимптотика: $$$\mathcal{O}((n + q) \log A)$$$.
Другое решение заключается в том, чтобы построить Дерево Отрезков на массиве $$$a$$$ на нахождение побитового ИЛИ чисел на отрезке. Асимптотика: $$$\mathcal{O}(n + q \log n)$$$
#include <bits/stdc++.h>
#define len(x) ((int) (x).size())
using namespace std;
typedef long long ll;
const ll INF = (1ll << 62);
const int INF_I = 0x3f3f3f3f;
void config_io() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cout << fixed;
cout.precision(20);
}
void solve();
int main() {
config_io();
auto start = chrono::high_resolution_clock::now();
solve();
auto end = chrono::high_resolution_clock::now();
#ifdef NEKSTAS_LOCAL
cerr << "Execution time: "
<< chrono::duration_cast<chrono::milliseconds>(end - start).count()
<< " ms" << endl;
#endif
return 0;
}
void solve() {
int n, q, z = 30;
cin >> n >> q;
vector<int> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
vector<vector<int>> p(n + 1, vector<int>(z, 0));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < z; ++j) {
p[i + 1][j] = p[i][j] + !!(a[i] & (1 << j));
}
}
for (int i = 0; i < q; ++i) {
int l, r;
cin >> l >> r;
l--;
int ans = 0;
for (int j = 0; j < z; ++j) {
ans += (p[r][j] - p[l][j] > 0) << j;
}
cout << ans << "\n";
}
}
[problem:417995E]
Автор задачи: Ilya_Is2022
Решение: Ilya_Is2022
Ожидается...
Ожидается...
[problem:417995F]
Это довольно стандартная задача на теорию чисел. Как было написано в условии, коэффициент перед $$$k$$$-м слагаемым в разложении $$$n$$$-й степени равен $$$C_k^n$$$, то есть, задача сводится к нахождению $$$C_k^n$$$ за $$$\mathcal{O}(1)$$$ или $$$\mathcal{O}(\log n)$$$ с предподсчётом за некоторую асимптотику.
Давайте посчитаем массив $$$f$$$ длины $$$n + 1$$$, где $$$f_i = i!$$$ по модулю $$$10^9 + 9$$$ ($$$i$$$ факториал). Это можно сделать следующей рекуррентной формулой: $$$f_0 = 1$$$, $$$f_i = f_{i-1} \times i\ \%\ M$$$, где $$$M = 10^9 + 9$$$.
Теперь давайте посчитаем число, обратное к $$$n!$$$ по модулю $$$M$$$. Это можно сделать с помощью бинарного возведения числа $$$n!$$$ в степень $$$M - 2$$$ по модулю $$$M$$$, либо с помощью расширенного алгоритма Евклида.
Теперь мы хотим посчитать массив $$$rf$$$ длины $$$n + 1$$$, где $$$rf_i = \frac{1}{n!}$$$. $$$rf_n$$$ мы посчитали чуть выше, а остальные элементы можно посчитать по формуле $$$rf_i = rf_{i+1} * i\ \%\ M$$$.
Теперь у нас есть посчитанные по модулю $$$M$$$ факториалы и обратные факториалы. Вспоминая, что $$$C_k^n = \frac{n!}{k! \times (n-k)!}$$$, мы можем понять, что $$$C_k^n = f_n \times rf_k \times rf_{n-k}$$$ по модулю $$$M$$$.
Мы научились отвечать на запросы за $$$\mathcal{O}(1)$$$ с предподсчётом за $$$\mathcal{O}(n + \log A)$$$.
Также существует решение за $$$\mathcal{O}(\log n)$$$ на запрос и предподсчётом за $$$\mathcal{O}(n)$$$.
Итоговая асимптотика: $$$\mathcal{O}(n + q + \log A)$$$
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
void config_io() {
ios_base::sync_with_stdio(false);
cout.tie(nullptr);
cin.tie(nullptr);
cout.precision(20);
cout << fixed;
}
const ll MOD = 1e9 + 9, MAX_N = 2e5 + 10;
vector<ll> f(MAX_N + 1);
vector<ll> rf(MAX_N + 1);
ll mul(ll a, ll b) {
return a * b % MOD;
}
ll add(ll a, ll b) {
return (a + b) % MOD;
}
ll pow(ll a, ll b) {
if (b == 0) return 1;
if (b % 2 == 0) {
ll v = pow(a, b / 2);
return mul(v, v);
}
return mul(a, pow(a, b - 1));
}
ll inv(ll a) {
return pow(a, MOD - 2);
}
ll comb(ll n, ll k) {
return mul(mul(f[n], rf[n - k]), rf[k]);
}
void solve() {
ll q, n, k;
cin >> q;
rf[0] = f[0] = 1;
for (int i = 1; i <= MAX_N; ++i) {
f[i] = mul(f[i - 1], i);
}
rf[MAX_N] = inv(f[MAX_N]);
for (int i = MAX_N - 1; i > 0; --i) {
rf[i] = mul(rf[i + 1], i + 1);
}
for (int i = 0; i < q; ++i) {
cin >> n >> k;
cout << comb(n, k) << "\n";
}
}
int main() {
config_io();
solve();
return 0;
}
[problem:417995G]
Автор задачи: Ilya_Is2022
Решение: Ilya_Is2022
Существует легенда, которая гласит, что Codeforces работает на хомяках, которые и вырабатывают электричество...
А Вы знали об этом?
Идейным решением данной задачи могли быть следующие ответы: Codeforces, Polygon, MikeMirzayanov.
Регистр написания данных ответов не имел значения :)
print("Codeforces")