ИИ ничего здесь не найдёт ограничение по времени н...
تم الإنشاء في: ٢٧ يونيو ٢٠٢٦
تم الإنشاء في: ٢٧ يونيو ٢٠٢٦
ИИ ничего здесь не найдёт
ограничение по времени на тест
1 секунда
ограничение по памяти на тест
256 мегабайт
В этой задаче отключены взломы.
У Milkcat2009 есть матрица a из n строк и m столбцов, состоящая из целых чисел 0 и 1. Строки пронумерованы от 1 до n, столбцы — от 1 до m. Элемент в i-й строке и j-м столбце обозначается как ai,j.
ИИ Milkcat2009 сканирует каждую подматрицу∗ матрицы a, состоящую из r строк и c столбцов. ИИ считает матрицу чистой, если побитовый XOR элементов в каждой такой подматрице равен 0.
Формально, матрица a является допустимой тогда и только тогда, когда для всех 1≤i≤n−r+1 и 1≤j≤m−c+1:
⨁x=ii+r−1⨁y=jj+c−1ax,y=0
где ⊕ обозначает суммирование с операцией побитового XOR.
Ваша задача — для нескольких наборов целых чисел n,m,r,c подсчитать количество чистых матриц из n строк и m столбцов при заданных размерах области сканирования r и c. Так как ответ может быть очень большим, вычислите его по модулю 998244353.
∗Подматрица матрицы получается удалением нескольких строк (с начала и/или конца) и/или нескольких столбцов (с начала и/или конца) из исходной матрицы.
Входные данные
Каждый тест состоит из нескольких наборов входных данных. В первой строке находится одно целое число t (1≤t≤104) — количество наборов входных данных. Далее следует описание наборов входных данных.
Каждый набор входных данных состоит из одной строки, содержащей четыре целых числа n,m,r,c (1≤r≤n≤109, 1≤c≤m≤109) — размеры матрицы и размеры области сканирования соответственно.
Выходные данные
Для каждого набора входных данных выведите единственное целое число — ответ по модулю 998244353.
напиши код на с++, без комментариев и с простыми названиями переменных, ОЧЕНБ ПОДРОБНО объясни идею и вообще почему и как этот код работает (и скажи какие темы изучить, лекции посмотреть и задачи мне порешать (и где), чтобы научиться самой решать такого плана задачи)
Идея: все условия — это линейные уравнения над полем GF(2), потому что XOR — это сложение по модулю 2.
Количество подходящих матриц равно:
Всего переменных:
Нужно понять, сколько независимых условий дают все r × c подматрицы.
Ответ:
по модулю 998244353.
Код:
cpp#include <bits/stdc++.h> using namespace std; using ll = long long; const ll mod = 998244353; ll binpow(ll a, long long b) { ll res = 1; while (b > 0) { if (b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return res; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { ll n, m, r, c; cin >> n >> m >> r >> c; ll x = n * m; ll y = (n - r + 1) * (m - c + 1); ll d = x - y; cout << binpow(2, d) << '\n'; } return 0; }
Почему это работает:
Матрица состоит из n * m битов. Каждый бит — переменная: 0 или 1.
Для каждой подматрицы r × c есть условие:
Это линейное уравнение над GF(2).
Всего таких подматриц:
Главный факт: все эти уравнения независимы.
Почему независимы?
Сначала посмотрим на одномерный случай. Например, есть строка длины m, и мы берём все отрезки длины c.
Матрица условий выглядит так:
text11100... 01110... 00111... ...
Каждая новая строка начинается с новой позиции. Поэтому у каждой строки есть свой первый ненулевой элемент, которого не было у предыдущих строк. Значит, эти строки линейно независимы.
Для двумерного случая каждое условие r × c — это произведение вертикального условия на горизонтальное. Ранг такой системы равен:
То есть каждое окно r × c действительно добавляет одно новое независимое ограничение.
Тогда число свободных переменных:
Каждую свободную переменную можно выбрать двумя способами: 0 или 1.
Значит:
Так как числа огромные, считаем степень быстрым бинарным возведением в степень за O(log(nm)).
Сложность:
при t ≤ 10000 это легко проходит за 1 секунду.
Что изучить, чтобы решать такие задачи:
GF(2).Где тренироваться:
Codeforces:
xor, linear algebra, math, constructive algorithms;Gaussian elimination over GF(2).Темы для поиска лекций:
Главный шаблон для таких задач:
Если есть k бинарных переменных и rank независимых XOR-условий, то количество решений:
1 задача
ограничение по времени на тест
2 секунды
ограничение по памяти на тест
256 мегабайт
В этой задаче отключены взломы.
Алиса и Боб играют в игру с массивом a, состоящим из n целых неотрицательных чисел. Алиса ходит первой.
В каждый ход текущий игрок должен выбрать массив из n неотрицательных целых чисел b=[b1,b2,…,bn], удовлетворяющий следующим условиям:
0≤bi≤ai для всех 1≤i≤n;
∑ni=1bi>0 (то есть массив b не состоит целиком из нулей);
b1⊕b2⊕…⊕bn=0, где ⊕ обозначает операцию побитового XOR.
После выбора массива b игрок обновляет массив a, выполняя ai←ai−bi для всех 1≤i≤n.
Игрок, который не может выполнить такую операцию, проигрывает.
Определите количество допустимых выборов массива b, которые Алиса может сделать в первый ход, гарантируя победу при условии, что оба игрока играют оптимально. Так как это число может быть большим, выведите ответ по модулю 998244353.
Входные данные
Каждый тест состоит из нескольких наборов входных данных. В первой строке находится одно целое число t (1≤t≤104) — количество наборов входных данных. Далее следует описание наборов входных данных.
Первая строка каждого набора входных данных содержит целое число n (1≤n≤106) — длину массива a.
Вторая строка каждого набора входных данных содержит n целых чисел a1,a2,…,an (1≤ai<230) — элементы массива a.
Гарантируется, что сумма n по всем наборам входных данных не превосходит 106.
Выходные данные
Для каждого набора входных данных выведите количество допустимых выборов массива b, которые Алиса может сделать в первый ход, гарантируя победу, по модулю 998244353.
2 задача
ограничение по времени на тест
2 секунды
ограничение по памяти на тест
256 мегабайт
В этой задаче отключены взломы.
За круглым столом сидят n человек, пронумерованных 1,2,3,…,n по часовой стрелке. Вы приготовили несколько подарков для раздачи среди них.
У каждого человека i есть вес ai и общее поле зрения d. Поле зрения человека i состоит из d людей, сидящих по часовой стрелке, и d людей, сидящих против часовой стрелки от него (всего 2d человек, не считая самого человека i).
Счастье, получаемое человеком i, определяется следующими правилами:
Если человек i получает подарок, и в его поле зрения находятся x человек, не получивших подарок, он получает x⋅ai счастья.
Если человек i не получает подарок, и в его поле зрения находятся x человек, получивших подарок, он теряет −x⋅ai счастья.
Вы хотите максимизировать суммарное счастье всех n человек. Найдите это максимальное значение.
Входные данные
Каждый тест состоит из нескольких наборов входных данных. В первой строке находится одно целое число t (1≤t≤104) — количество наборов входных данных. Далее следует описание наборов входных данных.
Первая строка каждого набора входных данных содержит два целых числа n и d (3≤n≤2⋅105, 1≤d<n2).
Вторая строка содержит n целых чисел a1,a2,…,an (1≤ai≤108), где ai — вес i-го человека.
Гарантируется, что сумма n по всем наборам входных данных не превосходит 106.
Выходные данные
Для каждого набора входных данных выведите единственное целое число — максимальное суммарное счастье.
напиши код на с++ для обеих задач, без комментариев с короткими названиями переменных, ОЧЕНЬ ПОДРОБНО объясни идеи и все строки кода. скажи какая из этих задач легче, особенно если у меня проблемы с пониманием битовых операций. и скажи что и где мне посмотреть/почитать/порешать, на какие темы и алгоритмы и тд чтобы научиться самой решать такие задачи
pythonfrom functools import lru_cache def moves(a): n=len(a) res=[] def rec(i,cur,x): if i==n: if any(cur) and x==0: res.append(tuple(a[j]-cur[j] for j in range(n))) return for v in range(a[i]+1): cur.append(v); rec(i+1,cur,x^v); cur.pop() rec(0,[],0) return res @lru_cache(None) def win(a): return any(not win(b) for b in moves(a)) for n in range(1,5): print("n",n) Ps=[] for vals in __import__('itertools').product(range(5), repeat=n): if not win(vals): Ps.append(vals) print(Ps[:50], len(Ps))
Ниже два решения. Вторая задача легче, особенно если плохо с битовыми операциями. Первая требует понять XOR-игру и проигрышные позиции.
cpp#include <bits/stdc++.h> using namespace std; using ll = long long; const ll mod = 998244353; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { int n; cin >> n; vector<ll> a(n); ll x = 0; for (int i = 0; i < n; i++) { cin >> a[i]; x ^= a[i]; } if (n == 1) { cout << 0 << '\n'; continue; } ll ans = 0; if (x == 0) ans++; for (int i = 0; i < n; i++) { ll y = x ^ a[i]; if (y < a[i]) ans++; } cout << ans % mod << '\n'; } return 0; }
Игрок выбирает массив b, такой что:
и хотя бы один b_i > 0.
Потом массив становится:
То есть после хода остаётся некоторый массив s, где:
Нам нужно посчитать ходы Алисы, после которых Боб окажется в проигрышной позиции.
Проигрышные позиции — это позиции, где не больше одного ненулевого числа.
Например:
text[0, 0, 0] [5, 0, 0] [0, 7, 0] [0, 0, 10]
Почему?
Если ненулевое число только одно, например:
text[5, 0, 0]
то любой ненулевой ход должен выбрать b, у которого XOR равен 0.
Но если можно уменьшать только одно число, то выбранный b будет выглядеть так:
text[x, 0, 0]
А XOR будет равен x.
Чтобы XOR был 0, нужно x = 0, но такой ход запрещён.
Значит, ходов нет.
А если ненулевых чисел хотя бы два, то можно сделать ход так, чтобы оставить не больше одного ненулевого числа. Поэтому такая позиция выигрышная.
После первого хода Алисы должен остаться массив s, в котором не больше одного ненулевого числа.
То есть возможны два случая.
После хода остаётся всё нулевое:
text[0, 0, 0, ..., 0]
Тогда Алиса забрала весь массив:
Такой ход допустим только если:
В коде общий XOR называется x.
Если x == 0, добавляем 1 к ответу.
cppif (x == 0) ans++;
После хода остаётся ровно одно ненулевое число.
Пусть оно остаётся на позиции i.
Тогда после хода:
texts_i = some positive value s_j = 0 для всех j != i
То есть Алиса забирает полностью все элементы, кроме i.
Обозначим:
Тогда XOR выбранного массива b должен быть равен 0.
XOR всех a_i равен x.
Если на позиции i мы вместо a_i берём y, то XOR массива b будет:
Нужно:
Отсюда:
В коде:
cppll y = x ^ a[i];
Теперь нужно, чтобы Алиса действительно что-то оставила на позиции i.
То есть:
А значит:
Если это выполнено, такой ход подходит:
cppif (y < a[i]) ans++;
n == 1?Если массив длины 1, то ход должен выбрать b1, и при этом:
потому что XOR из одного числа равен самому числу.
Но ненулевой ход запрещён. Значит, ходов вообще нет.
cppif (n == 1) { cout << 0 << '\n'; continue; }
cpp#include <bits/stdc++.h> using namespace std; using ll = long long; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { int n, d; cin >> n >> d; vector<ll> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } vector<ll> b(3 * n); for (int i = 0; i < 3 * n; i++) { b[i] = a[i % n]; } vector<ll> p(3 * n + 1, 0); for (int i = 0; i < 3 * n; i++) { p[i + 1] = p[i] + b[i]; } ll ans = 0; for (int i = 0; i < n; i++) { int j = i + n; ll l = p[j] - p[j - d]; ll r = p[j + d + 1] - p[j + 1]; ll s = l + r; ll cur = 2LL * d * a[i] - s; if (cur > 0) ans += cur; } cout << ans << '\n'; } return 0; }
Каждый человек либо получает подарок, либо нет.
Обозначим:
textg_i = 1, если человек i получил подарок g_i = 0, если не получил
Рассмотрим двух людей i и j, которые видят друг друга.
Есть 4 случая.
textg_i = 1 g_j = 1
Никто не видит человека без подарка.
Вклад пары:
textg_i = 0 g_j = 0
Никто не видит человека с подарком.
Вклад пары:
i получил подарок, j не получилТогда человек i получает:
А человек j теряет:
Итог:
j получил подарок, i не получилИтог:
Для каждой пары видящих друг друга людей выгодно, чтобы подарок получил человек с большим весом.
Но один человек участвует во многих парах, поэтому нужно аккуратно посчитать общий вклад.
Для пары i, j вклад можно записать так:
Проверим:
Если g_i = 1, g_j = 0:
Если g_i = 0, g_j = 1:
Если одинаково:
значит вклад 0.
Общая сумма:
Можно раскрыть скобки.
Для каждого человека i получится некоторый коэффициент:
Тогда итоговое счастье:
Теперь каждый g_i выбирается независимо.
Если:
то выгодно дать подарок человеку i.
Если:
то выгодно не давать.
Ответ:
Люди сидят по кругу.
Для человека i надо взять:
d человек слева;d человек справа.Чтобы не мучиться с переходом через конец массива, делаем массив длины 3n.
Например:
texta = [5, 2, 7] b = [5, 2, 7, 5, 2, 7, 5, 2, 7]
Центральная копия массива начинается с индекса n.
Поэтому человек i в центральной копии имеет индекс:
cppint j = i + n;
Сумму слева берём так:
cppll l = p[j] - p[j - d];
Сумму справа так:
cppll r = p[j + d + 1] - p[j + 1];
p — массив префиксных сумм.
Вторая задача легче.
Почему:
Первая задача сложнее, потому что там надо понять:
Если у тебя проблемы с битовыми операциями, сначала лучше разбирать задачу 2.
Для задачи 1:
bitmasksxorgamesДля задачи 2:
prefix sumsgreedymathЧто посмотреть:
С чего начать практику: