На форумі обговорюються лише питання, пов'язані з олімпіадою
Ви не зайшли.
Доброго времени суток всем! Поскольку 2-й тур закончился, давайте скидывать сюда решения задач. Я думаю, многим будет интересно почитать разбор.
Поза форумом
Задача Pixels2020
#include <bits/stdc++.h> using namespace std; //Dynamic Programming O(n*m) //VinnOlymp2020_tur_2_Pixels2020 //28/11/2020 18:58:53 int main() { int m, n, a, b, i, j; int img[500][700], pref[500][700]={}; cin >> n >> m >> a >> b; for(i=1; i<=n; i++) for(j=1; j<=m; j++) cin >> img[i][j]; pref[1][1]=img[1][1]; for(j=2; j<=m; j++) pref[1][j]=pref[1][j-1]+img[1][j]; for(i=2; i<=n; i++) pref[i][1]=pref[i-1][1]+img[i][1]; for(i=2; i<=n; i++) for(j=2; j<=m; j++) pref[i][j]=pref[i-1][j]+pref[i][j-1]-pref[i-1][j-1]+img[i][j]; int maxBright=0, minBright=a*b*255 + 1; for(i=a; i<=n; i++) for(j=b; j<=m; j++){ maxBright=max(maxBright, pref[i][j]-pref[i-a][j]-pref[i][j-b]+pref[i-a][j-b]); minBright=min(minBright, pref[i][j]-pref[i-a][j]-pref[i][j-b]+pref[i-a][j-b]); } cout << minBright << " " << maxBright << endl; return 0; }
Очевидно, что в этой задаче просто требуется найти прямоугольник с максимально сумой элементов, но, при этом, сделать данное действие быстро. Ну задача вполне базовая на ДП. Посчитываем так называемые интегральные суммы и находим максимальную и минимальную стоимость среди всех возможных прямоугольников. dp[i][j] - это сумма элементов подматрицы, левый верхний угол которой совпадает с клеткой [0][0], а правый нижний - в [i][j]. Дальше по формуле пересчёта.
Аналогичная задача на acmp.ru. Если не ошибаюсь, к ней Федор Меньшиков даже делал разбор.
https://acmp.ru/asp/do/index.asp?main=t … roblem=291
Відредаговано GeniusDP (2020-12-31 19:08:49)
Поза форумом
Задача Sum2020.
#include <bits/stdc++.h> using namespace std; int main() { const int MOD=1000000007; int n, s; cin >> n >> s; int *prev, *cur, *sw; prev = new int[1 + s]; cur = new int[1 + s]; for(int j=1; j<=s; j++) prev[j]=(j<=9)%MOD; for(int i=2; i<=n; i++){ for(int j=1; j<=s; j++){ cur[j]=0; for(int c=0; c<=9 && j-c>0; c++) cur[j]=(cur[j]+prev[j-c])%MOD; } //поменяли массивы местами sw=prev; prev=cur; cur=sw; } cout << prev[s]; return 0; }
Ну давайте разберём эту задачу: прежде всего - это ДП. Причём двумерное.
Давайте скажем, что dp[count][sum] - это количество чисел длины count и с суммой цифр sum.
Ну тогда инициализируем: Очевидно, что в строчке номер 1(одноцифровые числа) будет так: в столбиках 1-9 будет 1, дальше нули.
Ну понятно: ведь существует всего 1 одноцифровое число с суммой цифр, например, 5 - это 5.))) А вот одноцифровых чисел с суммой цифр больше 9 не существует - тоже весьма очевидно. Всё это - в следующей строчке.
for(int j=1; j<=s; j++) prev[j]=(j<=9)%MOD;
//И да, у меня в коде нет слова dp, но причина чуть-чуть позже.
Так. Дальше формула пересчёта.
dp[i][j]=<здесь должна быть сигма)>jє[0;9] : dp[i-1][j-c].
Ну типа суммируем все dp[i][j-c], где с - это все возможные цифры(ну 10 штук.)
Ок. А почему так, спросите? Резонно. Ну тут идея такова: будем продливать число длины (i-1) различными цифрами от 0 до 9. Тогда число будет иметь длину i и, что важно, сумма цифр увеличится на значение этой цифры. Так вот: если взять число , в котором кол-во цифр
и их сумма равны i-1 и j-c соответственно, то прибавив в конец данного числа цифру с, получим число с кол-вом цифр i и их суммой, равной j. А их количество равно dp[i][j]. Таким образом нам нужно просто просуммировать все КОЛИЧЕСТВА(наша динамика!) чисел длины i-1 и суммами цифр, на значение всех допустимых цифр "с" меньше текущего j.
Надеюсь, тут всё понятно. Не понятно - пишите в чат, ответим.)
Теперь почему нет двумерного массива.
Ну просто нам пришлось бы держать массив dp[1000][9000], что не представляется возможным (на заметку: можно где-то 1000х1000 как правило. Иначе - ошибка. Но у меня на компе даже 500х500 не тянет))) Поэтому, если Вы тестируете задачу у себя на компе, то не переживайте, что она вылетает от переполнения памяти: в проверочной системе компы - что надо).
Но эту проблему довольно легко решить: мы ведь при вычислении dp[i][j] использовали лишь значения из предыдущей строки(dp[i-1][...]),
значит и будем хранить лишь 2 строчки(линейных массива): prev - предыдущую и cur - текущую, как не трудно догадаться. Вычислив значение текущей, можем обменять местами указатели на динамические массивы за O(1) и использовать массивы повторно уже в другом "амплуа": на предыдущем шаге это был по факту массив предыдущей строчки, а на текущем - уже текущей.
Короче говоря, просто вместо хранения всей матрицы используем две её строки.
Как-то так. Надеюсь, что мои опусы были Вам интересны. Буду очень рад, если здесь ниже появятся вопросы(с радостью на них отвечу) и решения других задач, так как, окромясь этих двух, я не решил ничего(времени не хватило))) ).
PS: С наступающим 2021-м годом!!! Желаю всем, что бы сбылись все ваши мечты и осуществились планы на 21-й!!!
Відредаговано GeniusDP (2020-12-31 19:11:38)
Поза форумом
Задача Sum2020.
Складність О(n*s) - в найгіршому випадку при s = 9n/2. Найбільший час - 0.08 с (19 тест).
uses math; const p = 1000000007; var a, d: array[-9..9000] of longint; i, n, s, x, m: longint; begin read(n, s); if s > 9 * n then begin write(0); halt end; a[1] := 1; m := min(s, 9*n - s + 1); for i := 1 to n do begin for x := 1 to min(9*i, m) do begin d[x] := d[x-1] + a[x] - a[x-10]; //SuperGeniusDP :) if d[x] < 0 then inc(d[x], p) else if d[x] > p then dec(d[x], p); // not mod end; for x := 1 to min(9*i, m) do a[x] := d[x]; end; write(d[m]) end. //Паскаль рулит :)
Всім удачі в Новому році!
Відредаговано Беспредел (2021-01-01 10:58:18)
Поза форумом
Повнобальні рішення з короткими розборами. Частково повторюють ті, що вже викладені вище, але для повноти - нехай буде
Plant
Маємо всього 3 будівлі, тож можемо просто перебрати усі варіанти. При переборі будемо спочатку "склеювати" 2 будівлі і знаходити обмежуючий прямокутник для них. Далі сприймаємо цей прямокутник як одну будівлю і приклеюємо до нього третю будівлю.
В процесі перебору враховуумо наступні незалежні змінні:
- Кожна з будівель може бути в оригінальній орієнтації, або повернутою на 90 градусів (2 варіанта для кожної з будівель, кожен вибір незалежний, тож всього 2^3=8 варіантів)
- коли "склеюємо" 2 перші будівлі, ми можемо їх склеїти по вертикалі, або по горизонталі (2 варіанти)
- аналогічно, коли приклеюємо третю будівлю - можемо приклеїти по вертикалі, або по горизонталі (2 варіанти).
- порядок склеювання. Які будівлі клеїмо перші, а яку потім ліпимо до них. 3 варіанти: ((1, 2), 3), ((2, 3), 1), ((3, 1), 2)
Таким чином, всього маємо 96 варіантів розміщення. Їх і перевіряємо.
Асимптотика.
Час: O(1)
Пам'ять: O(1)
Код рішення на С++.
#include <iostream> #include <limits> #include <functional> using namespace std; typedef pair<int, int> rect; int area(rect r) { return r.first * r.second; } rect rotated(rect r) { return {r.second, r.first}; } rect get_v_bounding_box(rect a, rect b) { return {max(a.first, b.first), a.second + b.second}; } rect get_h_bounding_box(rect a, rect b) { return {a.first + b.first, max(a.second, b.second)}; } int get_min_bounding_box_area(rect a, rect b, rect c) { function<rect (rect, rect)> bb_functions[] { get_v_bounding_box, get_h_bounding_box }; int res = numeric_limits<int>::max(); for (auto f1 : bb_functions) { for (auto f2 : bb_functions) { rect boxes[] = { f1(f2(a, b), c), f1(f2(b, c), a), f1(f2(c, a), b), }; for (auto r : boxes) { res = min(res, area(r)); } } } return res; } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); rect rects[3]; for (auto &r : rects) { cin >> r.first >> r.second; } int res = numeric_limits<int>::max(); for (int rotation_mask = 0; rotation_mask < 1 << 3; ++rotation_mask) { auto bb_area = get_min_bounding_box_area( rotation_mask >> 0 & 1 ? rotated(rects[0]) : rects[0], rotation_mask >> 1 & 1 ? rotated(rects[1]) : rects[1], rotation_mask >> 2 & 1 ? rotated(rects[2]) : rects[2] ); res = min(res, bb_area); } cout << res << endl; }
Pixels2020
Нехай A - оригінальна вхідна матриця, так що A[i][j] - це колір пікселя в i-му рядку і j-му стовпчику.
Заведемо допоміжну матрицю S, елементи якої зберігатимуть суму значень пікселів у фрагменті з початку координат до поточного пікселя:
За допомогою цієї матриці ми можемо за константний час знаходити суму значень пікселів у будь-якому фрагменті. Сума значень пікселів у фрагменті з лівим верхнім кутом у координаті (x; y), та розмірами (h; w) дорівнюватиме
Обчислювати значення елементів допоміжної матриці можна прямо находу, по мірі зчитування вхідних даних, так само за константний час (для одного елемента).
Після того, як отримали цю допоміжну матрицю - пробігаємося по ній і шукаємо фрагмент з мінімальною та максимальними яскравостями відповідно. Оскільки розміри фрагмента фіксовані, пробігтися достатньо один раз.
Асимптотика.
Час: O(N*M)
Пам'ять: O(N*M)
Код рішення на С++.
#include <limits> #include <iostream> using namespace std; int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); const int MAX_N = 640; const int MAX_M = 480; int m, n, a, b; cin >> m >> n >> a >> b; static int s[MAX_M + 1][MAX_N + 1] = {}; for (int i = 1; i <= m; ++i) { for (int j = 1; j <= n; ++j) { cin >> s[i][j]; s[i][j] += s[i-1][j] + s[i][j-1] - s[i-1][j-1]; } } int max_s = numeric_limits<int>::min(); int min_s = numeric_limits<int>::max(); for (int i = 0; i <= m - a; ++i) { for (int j = 0; j <= n - b; ++j) { auto sum = s[i + a][j + b] - s[i] [j + b] - s[i + a][j] + s[i] [j]; max_s = max(max_s, sum); min_s = min(min_s, sum); } } cout << min_s << " " << max_s << endl; }
Sum2020
Розглянемо функцію g(k, s), таку, що g(k, s) дорівнює кількості k-цифрових чисел з сумою цифр s. Нехай ми знаємо значення цієї функції для усіх s при k = n-1. У такому разі ми можемо обчислити значення функції для k = n та довільного s наступним чином:
Тобто отримали рекурсивну формулу. Базою рекурсії будуть наступні випадки:
Реалізація такої рекурсивної функції "в лоб" матиме експоненційну складність через повторні обчислення. Тож для отримання адекватного часу роботи потрібно застосувати рекурсію з мемоізацією, або (бажано) динамічне програмування.
Рішення нижче реалізує ДП.
Асимптотика.
По часу: O(N * S)
По пам'яті: O(N * S), але при бажанні можна зробити O(S), оскільки у кожний момент часу нам потрібен лише попередній рядок матриці ДП.
Код рішення на С++.
#include <iostream> #include <algorithm> using namespace std; const long long MOD = 1000000007; int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); const int MAX_N = 1000; const int MAX_S = MAX_N * 9; int n, s; cin >> n >> s; static int dp[MAX_N + 1][MAX_S + 1]; dp[0][0] = 1; for (int i = 1; i <= n; ++i) { dp[i][0] = 0; } for (int i = 1; i <= s; ++i) { dp[0][i] = 0; } for (int i = 1; i <= n; ++i) { for (int j = 1; j <= s; ++j) { auto val = 0LL; for (int digit = 0, end = min(9, j); digit <= end; ++digit) { val += dp[i - 1][j - digit]; } dp[i][j] = val % MOD; } } cout << dp[n][s] << endl; }
Parket0
Візерунок можна умовно розділити на 4 зони:
- Центральна (зелена). Зона, яка повністю складається з "повних" блоків 5х5.
- Бокові (жовті). 4 стрічки, які прилягають до зеленої зони. Вздовж однієї з осей їх довжина кратна 5 і вони складаються з цілого числа "повних" блоків. Вдовж іншої осі - їх довжина строго менша 5.
- Кутові (червоні). Не містять жодного повного блока, п обох осях менші за 5. Одним кутом прилягають до зеленої зони.
Кожна з зон може мати нульові розміри. У більшості випадків це ні на що не впливає. З одним виключенням, про нього далі.
Будемо рахувати кількості дощечок у кожній зоні окремо.
Спочатку знайдемо координати кутів центральної зони. Знаючи їх ми зможемо знайти і координати всих інших частин.
Координати цих кутів - кратні п'яти і лежать всередині початкового візерунку. Відповідно, для того, щоб знайти лівий нижній кут центральної частини - ми округлюємо координати нижнього лівого кута загального візерунку до найближчого кратного 5 значення вгору. А для правого верхнього кута - координати правого верхнього кута загального візерунку до найближчого кратного 5 значення вниз.
Після цього підрахунок дощечок у кожній зоні - доволі прямолінійний.
Центральна зона:
Рахуємо кількість блоків 5х5 у зоні (їх ціла кількість, бо усі координати кратні 5). Кожна з цих зон містить 5 дощечок 5х1.
Стрічки:
Для кожної стрічки важливо знати 3 речі: довжина (та, що кратна 5), ширина (та, що менша 5), та з яких дощечок "починається" смужка - з повних 5х1, чи з порізаних. Наприклад на картинці ліва смужка починається з порізаних дощечок, а права - з повних.
Довжина та ширина знаходяться тривіально. А порізаність, чи не-порізаність першого блоку залежить від парності координат "округленого" кута (будь якого з двох), та від орієнтації смужки.
Вертикальні смужки починаються з порізаних дощечок, якщо координати кута мають різну парність. Горизонтальні - навпаки, якщо парність однакова.
Знаючи цю інформацію нескладно підрахувати дощечки в смужці. Нехай w - ширина смужки, а l - довжина в блоках (тобто довжина, поділена на 5).
Тоді якщо довжина парна - повних і порізаних блоків - однакова кількість. Інакше тих блоків, з якого почалася стрічка (порізаний, чи непорізаний) - на 1 більше.
Тобто повних дощечок 5х1 - (l + 1 - x)/2 * w, а порізаних дощечок w х 1 - (l + x)/2 * 5.
Де x = 1, якщо смужка починається з порізаних дощечок, або x = 0, якщо з цілих. Ділення мається на уваці цілочисельне (з округленням до цілих у напрямку до нуля).
І врешті решт, кути:
Для кутів достатньо знати розміри та напрямок дощечок. Розміри рахуютсья тривіально, напрямок - по аналогії з підрахунком "порізаності" першого блоку смужок.
Граничний випадок.
У випадку, коли увесь візерунок лежить всередині одного блоку вздовж будь-якої з координат - все поламається. Адже під час округлення у нас правий кут вийде лівішим за лівий, а верхній - нижчим за нижній. Наприклад, якщо лівий нижній куток візерунка лежав у координатах (7; 11), а правий верхній - у (9; 12), то після округлення виявиться, що у центральної частини координати лівого нижнього кута - (10; 15), а правого верхнього - (5; 10). Що, очевидно, нонсенс.
Щоб цього не сталося - у такому випадку ми просто "посунемо" увесь візерунок до границі блоку і переконаємось, що усі координати отримали адекватні значення (і розміри центральної частини стали нульовими, а не від'ємними).
Асимптотика.
По часу: O(1)
По пам'яті: O(1)
Код кінцевого рішення на С++.
#include <iostream> using namespace std; typedef unsigned long long ull; void countStripe(ull width, ull length, bool startsCut, ull *res) { if (!width) return; auto cnt5 = length / 5; auto cntCut = (cnt5 + startsCut) / 2 * 5; auto cntFull = (cnt5 + !startsCut) / 2 * width; res[4] += cntFull; res[width - 1] += cntCut; } void countCorner(ull width, ull height, bool horizontal, ull *res) { if (!width || !height) return; if (horizontal) { res[width - 1] += height; } else { res[height - 1] += width; } } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); ull xmin, xmax, ymin, ymax; ull res[5] = {0, 0, 0, 0, 0}; cin >> xmin >> xmax >> ymin >> ymax; auto xminRound = (xmin + 4) / 5 * 5; auto yminRound = (ymin + 4) / 5 * 5; auto xmaxRound = xmax / 5 * 5; auto ymaxRound = ymax / 5 * 5; auto fixNarrow = [](ull &minRound, ull &maxRound, ull &min, ull &max){ if (minRound > maxRound) { minRound = maxRound; max -= min - minRound; min = minRound; } }; fixNarrow(xminRound, xmaxRound, xmin, xmax); fixNarrow(yminRound, ymaxRound, ymin, ymax); res[4] = (xmaxRound - xminRound) * (ymaxRound - yminRound) / 5; countStripe(xminRound - xmin, ymaxRound - yminRound, (xminRound ^ yminRound) & 1, res); countStripe(yminRound - ymin, xmaxRound - xminRound, ~(xminRound ^ yminRound) & 1, res); countStripe(xmax - xmaxRound, ymaxRound - yminRound, (xmaxRound ^ ymaxRound) & 1, res); countStripe(ymax - ymaxRound, xmaxRound - xminRound, ~(xmaxRound ^ ymaxRound) & 1, res); countCorner(xminRound - xmin, yminRound - ymin, ~(xminRound ^ yminRound) & 1, res); countCorner(xmax - xmaxRound, yminRound - ymin, (xmaxRound ^ yminRound) & 1, res); countCorner(xmax - xmaxRound, ymax - ymaxRound, ~(xmaxRound ^ ymaxRound) & 1, res); countCorner(xminRound - xmin, ymax - ymaxRound, (xminRound ^ ymaxRound) & 1, res); for (auto n : res) { cout << n << " "; } cout << endl; }
Fixshow
Розглянемо функцію f(x, y), яка показує мінімальний час, через який будуть чутися всі звуки одночасно у точці з координатами (x; y):
Наша задача - знайти мінімум цієї функції.
По-перше, можна помітити, що у функції немає локальних мінімумів, лише глобальний. Якщо ми стоїмо в ньому, то рухаючись у будь-якому напрямку значення функції ніколи не спадатиме (адже навіть якщо ми наближаємося до одного з синтезаторів - ми віддаляємося від інших і ці інші починають "домінувати"). Більше того, якщо ми зафіксуємо будь-яку координату, то отримана функція одного аргумента буде поводити себе так само.
Тобто функція є унімодальною і ми можемо застосувати вкладений тернарний пошук для пошуку відповіді з необхідною (або навіть більшою) точністю.
Асимптотика.
Час: O(N), але формально там ще два логарифма: O(Log(D_X) * Log(D_Y) * N), де D_X і D_Y - різниця між максимальною та мінімальною X- та Y-координатами синтезаторів відповідно.
Пам'ять: O(N)
Код рішення на С++.
#include <iostream> #include <cmath> #include <functional> #include <iomanip> using namespace std; using std::placeholders::_1; double ternary_search(double l, double r, double eps, function<double (double)> f){ while (r - l > eps) { auto m1 = l + (r - l) / 3; auto m2 = r - (r - l) / 3; auto r1 = f(m1); auto r2 = f(m2); if (r1 > r2) { l = m1; } else { r = m2; } } return (l + r) / 2; } struct Synth { double x; double y; double t; }; int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); const double MIN_COORD = -1e6; const double MAX_COORD = 1e6; const double EPS = 1e-6; Synth s[555]; int n; double c; cin >> n; for (int i = 0; i < n; ++i) { cin >> s[i].x >> s[i].y >> s[i].t; } cin >> c; auto getTime = [=](double x, double y) { double res = 0; for (int i = 0; i < n; ++i) { res = max(res, s[i].t + hypot(s[i].x - x, s[i].y - y) / c); } return res; }; auto getY = [=](double x) { return ternary_search(MIN_COORD, MAX_COORD, EPS, bind(getTime, x, _1)); }; auto x = ternary_search(MIN_COORD, MAX_COORD, EPS, [=](double x) { return getTime(x, getY(x)); }); auto y = getY(x); auto t = getTime(x, y); cout << fixed << setprecision(6) << x << ' ' << y << ' ' << t << endl; }
Формули відрендерені за допомогою https://quicklatex.com/
Відредаговано Dim_ov (2021-01-01 03:06:25)
Поза форумом
Задача Plant
Об'єднуємо 2 прямокутника - 4 варіанти, потім з третім - ще 4. Разом 16. І 3 варіанти вибору перших двох. Разом 48.
uses math; var a, b: array[1..3] of longint; i, s: longint; Procedure U1(a1, b1, a2, b2: longint); begin s := min(s, (a1 + a2) * max(b1, b2)) end; Procedure U(a1, b1, a2, b2, k: longint); var a12, b12: longint; begin a12 := a1 + a2; b12 := max(b1, b2); U1(a12, b12, a[k], b[k]); U1(a12, b12, b[k], a[k]); U1(b12, a12, a[k], b[k]); U1(b12, a12, b[k], a[k]); end; Procedure U2(i, j, k: longint); begin U(a[i], b[i], a[j], b[j], k); U(a[i], b[i], b[j], a[j], k); U(b[i], a[i], a[j], b[j], k); U(b[i], a[i], b[j], a[j], k); end; begin for i := 1 to 3 do read(a[i], b[i]); s := maxlongint; U2(1, 2, 3); U2(1, 3, 2); U2(2, 3, 1); write(s) end. //ясно, понятно
Поза форумом
Plant
Та же идея, только расположения занумерованы и перебираются в цикле.
#include <cstdio> #include <algorithm> using std::scanf; using std::printf; using std::min; using std::max; int main() { int c[6],t[6]; int b=1000000000; for(int j=0;j<6;++j) scanf("%d",&(c[j])); for(int i=0;i<24;++i) { for(int j=0;j<6;++j) t[j]=c[((j+(i/8)*2)^((i>>(j/2))&1))%6]; b=min(b,(t[0]+t[2]+t[4])*max(max(t[1],t[3]),t[5])); b=min(b,(max(t[0],t[2])+t[4])*max(t[1]+t[3],t[5])); } printf("%d",b); return 0; }
Sum2020
Если и здесь использовать кумулятивную сумму, то от суммирования по 10 цифрам можно избавиться: в таблице хранится "количество i-значных числел с суммой цифр, не превышающей j".
#include <cstdio> using std::scanf; using std::printf; unsigned t[2][10000]; int main() { const unsigned M=1000000007u; int n,s; unsigned *p,*c; scanf("%d%d",&n,&s); for(int i=0;i<=n;++i) { p=t[i&1]+10; c=t[(i+1)&1]+10; c[0]=1; for(int j=1;j<=s;++j) c[j]=(c[j-1]+p[j]-p[j-10]+M)%M; } printf("%d",((c[s]-c[s-1])-(p[s]-p[s-1])+2*M)%M); return 0; }
Parket0
#include <cstdio> #include <algorithm> using std::scanf; using std::min; using std::max; int main() { long long xmin,ymin,xmax,ymax; long long ret[5]={0,0,0,0,0}; scanf("%lld%lld%lld%lld",&xmin,&xmax,&ymin,&ymax); long long X0=xmin/5,Y0=ymin/5,X1=(xmax-1)/5,Y1=(ymax-1)/5; for(long long X=X0,dX=1;X<=X1;X+=dX) { dX=((X>X0&&X<X1)?X1-X0-1:1); for(long long Y=Y0,dY=1;Y<=Y1;Y+=dY) { dY=((Y>Y0&&Y<Y1)?Y1-Y0-1:1); long long D=dX*dY,P=(X^Y)&1; long long D1=(D+P)/2,D0=D-D1; long long x0=max(xmin-5*X,0LL),y0=max(ymin-5*Y,0LL),x1=min(xmax-5*X,5LL),y1=min(ymax-5*Y,5LL); int d0=(y1-y0),d1=(x1-x0); ret[d0-1]+=D1*d1; ret[d1-1]+=D0*d0; } } printf("%lld %lld %lld %lld %lld",ret[0],ret[1],ret[2],ret[3],ret[4]); return 0; }
Поза форумом
Якщо хочете ефективніше розв'язувати подібні задачі і покращити свої знання та навички, навчитися писати якісний код і отримати круту роботу, раджу звернути увагу на онлайн-курси https://stud-point.com/, де за невелику суму ви опануєте безліч корисних навичок у цікавій вам сфері. Не зволікайте і почніть втілювати свою мрію якнайшвидше!
Поза форумом