Задача A. Идея FairyWinx
В оптимальном ответе максимальное количество цифр, так что нужно использовать только цифры $$$1,2$$$.
Чередуйте эти цифры, чтобы не было соседних одиннаковых цифр.
Так как мы хотим максимизировать нужное нам число, найдем сначало самое длинное подходящее число. Очевидно, что для этого лучше использовать только цифры $$$1$$$ и $$$2$$$. Поэтому ответ всегда имеет вид $$$2121\ldots$$$ или $$$1212\ldots$$$. Первый вариант оптимален, когда $$$n$$$ имеет остаток $$$2$$$ или $$$0$$$ по модулю $$$3$$$, в противном случае оптимален второй вариант.
Ниже приведен пример аккуратной реализации.
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n;
cin >> n;
int type;
if (n % 3 == 1)
type = 1;
else
type = 2;
int sum = 0;
while (sum != n) {
cout << type;
sum += type;
type = 3 - type;
}
cout << '\n';
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int t;
cin >> t;
while (t--)
solve();
}
Задача B. Идея FairyWinx
Что представляет собой картинка, если ответ на задачу "YES".
Подумайте над квадратом размера $$$2 \times 2$$$.
Заметим, что ответ на задачу "YES" тогда и только тогда, когда картинка предствляет из себя какое-то количество непересекающихся прямоугольников. Теперь посмотрим в этом случае на все квадраты размера $$$2 \times 2$$$, заметим, что в каждом из них не может быть ровно $$$3$$$ закрашенных клетки.
Также понятно, что если найдутся $$$3$$$ таких клетки, то найдутся два пересекающихся прямоугольника. Поэтому нужно просто проверить, есть ли квадрат $$$2 \times 2$$$, в котором ровно $$$3$$$ закрашенных клетки.
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n, m;
cin >> n >> m;
vector<vector<int>> a(n, vector<int> (m));
for (int i = 0; i < n; ++i) {
string s;
cin >> s;
for (int j = 0; j < m; ++j) {
a[i][j] = s[j] - '0';
}
}
for (int i = 0; i < n - 1; ++i) {
for (int j = 0; j < m - 1; ++j) {
int sum = a[i][j] + a[i][j + 1] + a[i + 1][j] + a[i + 1][j + 1];
if (sum == 3) {
cout << "NO\n";
return;
}
}
}
cout << "YES\n";
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int t;
cin >> t;
while (t--)
solve();
}
Задача C. Идея FairyWinx
Ответ всегда есть, когда правая верхняя клетка покрашена в белый цвет.
Представьте, что у вас есть только прямоугольники размера $$$1 \times 2$$$.
Закрашивайте клетки с "конца".
По условию, если левая верхняя клетка покрашена в черный цвет, то мы не можем так покрасить. Иначе можно. Давайте будем красить клетки в следующем порядке: $$$(n, m), (n, m - 1), \ldots, (n, 1), (n - 1, m), \ldots (1, 1)$$$.
Пусть клетку $$$(i, j)$$$ нужно покрасить в черный цвет, тогда если $$$j > 1$$$, то просто покрасим прямоугольник $$$(i, j - 1)$$$, $$$(i, j)$$$. Иначе, если $$$j = 1$$$, то мы покрасим прямоугольник $$$(i - 1, j)$$$.
После такой операции никакие клетки, которые мы красили до этого, не перекрасятся, так как у них одна координата больше нашей, а сама клетка покрасится в черный цвет.
Таким образом мы умеем красить таблицу за максимум $$$n \cdot m - 1$$$ операций.
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n, m;
cin >> n >> m;
vector<vector<int>> a(n, vector<int> (m));
for (int i = 0; i < n; ++i) {
string s;
cin >> s;
for (int j = 0; j < m; ++j)
a[i][j] = s[j] - '0';
}
vector<array<int, 4>> ans;
if (a[0][0] == 1) {
cout << -1<< '\n';
return;
}
for (int j = m - 1; j >= 0; --j) {
for (int i = n - 1; i >= 0; --i) {
if (a[i][j]) {
if (i != 0) {
ans.push_back({i, j + 1, i + 1, j + 1});
} else {
ans.push_back({i + 1, j, i + 1, j + 1});
}
}
}
}
cout << ans.size() << '\n';
for (auto i : ans) {
cout << i[0] << ' ' << i[1] << ' ' << i[2] << ' ' << i[3] << '\n';
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int t;
cin >> t;
while (t--)
solve();
}
Задача D. Идея FairyWinx
Число красивое только в том случае, если оно кратно $$$d$$$, но не кратно $$$d^2$$$
Давайте решим более общую задачу: посчитать количество таких разбиений.
Эта задача решается динамическим программированием.
Храните в динамике оставшееся число, а также последний делитель.
Давайте решим более сложную задачу: посчитать количество разбиений на такие множители.
Заметим, что это несложно решается диническим программированием. Пусть $$$dp_{n, d}$$$ — количество разложений на множители, если у нас осталось число разложить число $$$n$$$, а до этого мы поделили на число $$$d$$$. Перебирем все такие красивые числа $$$i \geq d$$$, которые делят $$$n$$$, тогда $$$dp_{n / i, i} += dp_{n, d}$$$.
Заметим, что в это случае мы каждый вариант учли ровно один раз, поскольку мы считаем делители в порядке их увеличения.
Пусть $$$C$$$ — это количество делителей числа $$$x$$$, а $$$V$$$ — это количество красивых делителей числа $$$x$$$. Тогда это работает за $$$O(С \cdot V)$$$ или $$$O(C \cdot V^2 \cdot log)$$$ в зависимости от реализации (так как $$$n$$$ всегда является делителем числа $$$x$$$), но все это легко заходит, так как $$$V$$$ не больше (посчитать максимальное значение).
#include <bits/stdc++.h>
using namespace std;
bool good(int i, int d) {
return i % d == 0 && i % (1ll * d * d) != 0;
}
void solve() {
int x, d;
cin >> x >> d;
map<pair<int, int>, int> dp;
dp[{x, 1}] = 1;
int res = 0;
vector<int> del;
for (int i = 1; i * i <= x; ++i) {
if (x % i == 0) {
if (good(i, d))
del.push_back(i);
if (x != i * i && good(x / i, d))
del.push_back(x / i);
}
}
while (dp.size()) {
auto z = *dp.rbegin();
if (z.first.first == 1) {
res += z.second;
}
for (auto i : del) {
if (z.first.first % i == 0 && i >= z.first.second) {
dp[{z.first.first / i, i}] = min(dp[{z.first.first / i, i}] + z.second, 2);
}
}
dp.erase(z.first);
}
if (res == 1)
cout << "NO\n";
else
cout << "YES\n";
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int t;
cin >> t;
while (t--)
solve();
}
Рассмотрим случаи
Пусть $$$x = d^a \cdot b$$$. Где $$$b$$$ не кратно $$$d$$$.
Тогда рассмотрим несколько случаев:
$$$a = 1$$$. Тогда $$$a$$$ — это красивое число, поскольку любое число кратное $$$d^2$$$ можно разложить на $$$d \cdot (a / d)$$$, каждое из которых красиове, а число кратное только $$$d$$$, очевидно, разложить нельзя. Значит в этом случае ровно один вариант.
$$$b$$$ — составное, тогда, очевидно, мы можем разложить несколькими вариантами, если $$$a \neq 1$$$.
$$$d$$$ — простое. Если $$$b$$$ простое, то утверждение — у нас только один вариант разложить число. Так как каждый красивый множитель вида $$$d \cdot k$$$. Но поскольку $$$d$$$ простое, то никаких других способов разложить нет, кроме как добавить множитель из $$$b$$$, а поскольку $$$b$$$ простое, то все эти варианты будут равны до перестановки.
$$$d$$$ — составное и не является степенью простого. Если $$$a \leq 2$$$, то этот случай никак не отличается от прошлого, так как мы все равно должны получить два красивых множителя и все они будут просто равны $$$d$$$. Иначе пусть $$$d = p \cdot q$$$, где $$$gcd(p, q) = 1$$$. Тогда мы можем сделать число $$$p \cdot q^{b - 1}$$$ и $$$p^{b - 1} \cdot q$$$. А также $$$q \cdot p, q \cdot p, \ldots , q \cdot p$$$, в этом случае у нас разное количество делителей, так что эти варианты будут разные, а значит у нас несколько вариантов в этом случае.
$$$d$$$ — степень простого числа. Тогда $$$d = p^k$$$. Утверждение, если $$$d = p^2$$$, а $$$x = p^7$$$, то нельзя разложить несколькими способами, иначе, если $$$a > 2$$$ и $$$k > 1$$$, то посмотрим на разбиение $$$p^{2k - 1}, p^{k + 1}, p^k, \ldots , p^k$$$, понятно, что если $$$k > 2$$$, то даже если $$$b = p$$$, то множитель $$$p^{k + 2}$$$ до сих пор будет красивым, поэтому это не отличается от составного $$$d$$$ в прошлом случае. Иначе, если $$$k = 2$$$, то если $$$a = 3$$$ и $$$b = p$$$, то ничего добавить нельзя, а иначе у нас будет возможность выбрать $$$3$$$ множителя $$$p^k$$$, а остальное как-то разложить (так как в этом случае $$$a > 3$$$, то хотя бы еще один множитель будет) и добавить туда $$$b$$$. А эти 3 множителя мы можем разложить на $$$2$$$ или $$$3$$$ множителя, как написано выше. Поэтому единственный уникальный случай, когда $$$d$$$ — степень простого, это $$$d = p^2, x = p^7$$$.
#include <bits/stdc++.h>
using namespace std;
int prime(int x) {
for (int i = 2; i * i <= x; ++i) {
if (x % i == 0)
return i;
}
return -1;
}
void solve() {
int x, d;
cin >> x >> d;
int cnt = 0;
while (x % d == 0) {
++cnt;
x /= d;
}
if (cnt == 1) {
cout << "NO\n";
return;
}
if (prime(x) != -1) {
cout << "YES\n";
return;
}
if (prime(d) != -1 && d == prime(d) * prime(d)) {
if (x == prime(d) && cnt == 3) {
cout << "NO\n";
return;
}
}
if (cnt > 2 && prime(d) != -1) {
cout << "YES\n";
return;
}
cout << "NO\n";
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int t;
cin >> t;
while (t--)
solve();
}
Задача E. Идея FairyWinx
После каждой операции максимальный номер всегда увеличивается на конкретное число.
Ученики с номером большим $$$n$$$ нас не интересуют.
Представьте, что школьников не выгоняют, но в каждый момент времени нас просто интересует школьник с минимальным номером. Очевидно, что ответ в этом случае никак не поменяется.
Поймите, что каждый школьник после всех операций перейдет за одну конкретную парту.
Напишите жадник
После каждого урока номер человека с максимального номера увеличивается на количество парт, куда никто не переходит. Поэтому можно легко вычислить сколько прошло времени с самого начала, пусть это число $$$k$$$.
Тогда давайте представим, что школьников не выгоняют, а в каждый момент времени нас просто интересует школьник с минимальным номером. Очевидно, что ответ в этом случае никак не поменяется.
Пусть $$$to_i$$$ — это парта, в которую перейдет школьник после $$$k$$$ пересадок, изначально сидевший за $$$i$$$ партой. Это стандартная задача, которую можно решить при помощи бинарный подъемов или не самого приятного dfs c выделением циклов и подобным. (но последнее мы не рекомендуем вам писать), Определим множество $$$V_i$$$, как множество всех чисел $$$j$$$, где $$$to_j = i$$$.
Пусть стартовая расстановка школьника — это перестановка $$$b$$$, тогда поймем, что если за $$$i$$$ парту кто-то пересаживается после $$$k$$$ операций, то значение в ней это — минимальное значение в $$$V_i$$$. А если за нее никто не пересаживается, то в ней просто будет всегда сидеть школьник с одиннаковым номером, вне зависимости от начальной рассадки. После этого не сложно покзаать оптимальную стартовую рассадку школьников.
Пусть $$$s$$$ — это множество школьников, для которых мы пока не выбрали парту за которой они сидят. Будем перебирать $$$i$$$ от $$$1$$$ до $$$n$$$ по возрастанию. Тогда нужно понять, кто должен сидеть за $$$i$$$ партой.
Если мы знаем, что существует парта, для которой должно выполняться $$$min(V_i) = i$$$, то мы должны посадить за $$$i$$$ парту школьника с минимальным номером из $$$V_i$$$, а оставшихся людей мы можем садить за любые парты с номером большим $$$i$$$, поэтому добавим в множество $$$s$$$ всех остальных школьников. А иначе нам нужно просто взять человека из $$$s$$$ с минимальным номером и посадить его за место под номером $$$i$$$, а затем просто удалить его из множества $$$s$$$.
#include <bits/stdc++.h>
using namespace std;
const int K = 30;
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int n;
cin >> n;
vector<int> cnt(n);
vector<vector<int>> up(n, vector<int> (K));
for (int i = 0; i < n; ++i) {
int a;
cin >> a;
--a;
++cnt[a];
up[i][0] = a;
}
for (int k = 1; k < K; ++k) {
for (int i = 0; i < n; ++i) {
up[i][k] = up[up[i][k - 1]][k - 1];
}
}
vector<int> a(n);
int cnt_bad = 0;
for (int i = 0; i < n; ++i) {
cin >> a[i];
if (!cnt[i]) {
++cnt_bad;
}
}
int k = (*max_element(a.begin(), a.end()) - n) / cnt_bad;
vector<vector<int>> add(n);
for (int i = 0; i < n; ++i) {
int v = i, level = k;
for (int j = K - 1; j >= 0; --j) {
if (level >= (1 << j)) {
level -= (1 << j);
v = up[v][j];
}
}
add[a[v] - 1].push_back(i);
}
set<int> now;
vector<int> ans(n);
for (int i = 0; i < n; ++i) {
if (add[i].size()) {
int res = *min_element(add[i].begin(), add[i].end());
for (int j : add[i]) {
if (j != res) {
now.emplace(j);
}
}
ans[res] = i + 1;
} else {
ans[*now.begin()] = i + 1;
now.erase(*now.begin());
}
}
for (int i : ans)
cout << i << ' ';
cout << '\n';
}
Задача F. Идея Igorbunov
Осознайте, что максимальный элемент всегда является "перегибом" первой последовательности.
Можно предположить, что "перегиб" второй подпоследовательности всегда будет левее максимального элемента (если что, можно будет потом просто развернуть массив).
Всего у нас существует $$$3$$$ момента времени — обе подпоследовательности возрастают, первая убывает, а вторая возрастает, или обе подпоследовательности убывают.
Первый и третий случай решаются очевидной жадностью.
Для второго можно просто написать динамику.
Перегиб последовательности — это максимальное число в подпоследовательности. Тогда заметим, что в первой подпоследовательности перегибом будет максимальное число в нашем массиве, пусть его позиция в массиве — $$$ind$$$.
Тогда давайте для удобства скажем, что перегиб второй подпоследовательности будет правее максимального элемента. (потом развернем массив и запустим решение еще один раз).
В этом случае у нас будет $$$3$$$ состояния: обе подпоследовательности возрастают, первая убывает, а вторая возрастает или обе подпоследовательсности убывают.
Решим для начала первый случай:
Пусть $$$dp1_i$$$ — минимально возможный максимальный элемент в подпоследовательности, которая не содержит $$$i$$$ элемент. Она считается не сложно. Если $$$dp1_{i - 1} < a_{i}$$$, то $$$dp1_{i} = min(dp1_{i}, a_{i - 1})$$$, так как в этом случае мы можем добавить $$$i$$$ элемент в подпоследовательность, которая не содержит элемент $$$i - 1$$$. Аналогично, если $$$a_{i - 1} < a_{i}$$$, то $$$dp1_{i} = min(dp1_{i}, dp1_{i - 1})$$$.
Третий случай считается анологично, но только его нужно считать с конца. (Этот массив будет $$$dp3$$$)
Теперь разберемся со вторым случаем:
Пусть $$$dp2_{i, 0}$$$ — минимально возможный последний элемент во второй подпоследовательности, если $$$i$$$ элемент принадлежит первой подпоследовательности. И $$$dp2_{i, 1}$$$ — максимально возможный последний элемент в первой подпоследовательности, если $$$i$$$ элемент принадлежит второй подпоследовательности. Есть несколько вариантов. Если $$$i$$$ и $$$i - 1$$$ лежат в одинаковых и разных подпоследовательностях. И мы будем считать для $$$i \leq ind$$$, поскольку до этого участка обе подследовательности возрастают, а это уже другой посчитанный случай. И тогда не сложно получить формулы пересчета:
- $$$dp2_{ind, 0} = dp1_{ind}$$$, по определению $$$dp2_{ind, 0}$$$
- Если $$$a_{i - 1} > a_i$$$, то $$$dp2_{i, 0} = min(dp2_{i, 0}, dp2_{i - 1, 0})$$$.
- Если $$$dp2_{i - 1, 1} > a_i$$$, то $$$dp2_{i, 0} = min(dp2_{i, 0}, a_{i - 1})$$$.
- Если $$$a_{i - 1} < a_{i}$$$, то $$$dp2_{i, 1} = max(dp2_{i, 1}, dp3_{i - 1, 1})$$$.
- Если $$$dp2_{i - 1, 0} < a_i$$$, то $$$dp2_{i, 1} = max(dp2_{i, 1}, a_{i - 1})$$$.
Теперь поймем, что элемент с номером $$$i$$$ может быть перегибом второй подпоследовательности, если $$$i > ind$$$, а также $$$dp2_{i, 1} > dp3_{i}$$$. То есть мы можем перейти из второго состояния в третье.
#include <bits/stdc++.h>
using namespace std;
const int inf = 1e9 + 228;
int solve (int n, vector<int> a) {
int ind = max_element(a.begin(), a.end()) - a.begin();
vector<int> dp1(n, inf);
dp1[0] = -1;
for (int i = 1; i <= ind; ++i) {
if (a[i] > dp1[i - 1])
dp1[i] = min(dp1[i], a[i - 1]);
if (a[i] > a[i - 1])
dp1[i] = min(dp1[i], dp1[i - 1]);
}
vector<int> dp2(n, inf);
dp2[n - 1] = -1;
for (int i = n - 2; i >= ind; --i) {
if (a[i] > dp2[i + 1])
dp2[i] = min(dp2[i], a[i + 1]);
if (a[i] > a[i + 1])
dp2[i] = min(dp2[i], dp2[i + 1]);
}
vector<array<int, 2>> dp3(n, {inf, -inf});
dp3[ind][0] = dp1[ind];
int ans = 0;
for (int i = ind + 1; i < n; ++i) {
if (a[i - 1] > a[i])
dp3[i][0] = min(dp3[i][0], dp3[i - 1][0]);
if (dp3[i - 1][1] > a[i])
dp3[i][0] = min(dp3[i][0], a[i - 1]);
if (a[i - 1] < a[i])
dp3[i][1] = max(dp3[i][1], dp3[i - 1][1]);
if (dp3[i - 1][0] < a[i])
dp3[i][1] = max(dp3[i][1], a[i - 1]);
if (dp3[i][1] > dp2[i])
++ans;
}
return ans;
}
signed main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; ++i)
cin >> a[i];
int ans = solve(n, a);
reverse(a.begin(), a.end());
cout << ans + solve(n, a) << '\n';
}
Как соавтор......
Second case in F can be done greedy as well and only slightly less straightforward. We should be looking at two next elements instead of one and if $$$a_{i+1}>a_{i+2}$$$ then we should always add $$$a_{i+1}$$$ to a decreasing subsequence if possible, and vice versa.
That was quick! Nice round! Great Problems!
Problem C, hint 1:
I think you meant the upper left cell
I solved D in a pretty clumsy way without managing to come up with any of the nice math. I'm not sure if it's correct. Can somebody try to explain why it works or if it's wrong?
First you factorize x, then remove the non-multiples of d. These are all the good numbers that are candidates for multiplying to x. Let's let N be the length of these remaining good numbers. N ~ O(sqrt(x))
Now, we want to determine which ones of these are beautiful. After running some examples in my head, it seemed like for each good number g, we can just check to see if g/d is also good. If g/d is good, then g is not beautiful. Otherwise, g is beautiful. We can do this in O(N) or O(N log N) with hashing/sorting.
Now we have our remaining beautiful numbers. We just need to find 2 different ways to multiply to x. I tried locally with some huge numbers and the length of the remaining beautiful numbers is very small (around 15-20 for x=1e9). So i just did backtracking dfs over the numbers and divided until i got to 1.
This passed in a pretty reasonable amount of time. Please let me know if it's wrong.
Here is submission: https://mirror.codeforces.com/contest/1647/submission/149324001
.
Why all your submission are skipped
Yeah After cheating. Your all submissions are skipped . And we all know what that means right ??.
После этих слов в разборе случаев в Д начался настоящий кошмар :)
In problem D, according to definition, if d=2 then 16 can be a beautiful number because 16 is a good number (multiple of 2) and 16 cannot be represented a product of two good numbers but according to tutorial beautiful number is not divisible by d*d. Where I am wrong?
16=16*1 16=8*2 16=4*4
These are the possible cases, none of them has both the numbers good on right hand side
it can, 16 = 2*8
Ah! Got it, Don't know why I was thinking wrong.
Problem D, can someone prove or explain in more details why we can't factor in two ways if d = p^2 and x = p^7?
If we try to represent $$$x$$$ as the product of three numbers, we end up with the set $$$\{p^2,p^2,p^3\}$$$. If we try to move the extra $$$p$$$ factor, the resulting set is the same.
If we try to represent as $$$x$$$ as the product of two numbers, we end up with the set $$$\{p^3,p^4\}$$$, however $$$p^4 = (p^2)^2$$$, which is not allowed.
If you are/were getting a WA/RE verdict on problems from this contest, you can get the smallest possible counter example for your submission on cfstress.com. To do that, click on the relevant problem's link below, add your submission ID, and edit the table to increase/decrease the constraints.
If you are not able to find a counter example even after changing the parameters, reply to this thread, mentioning the contest_id, problem_index and submission_id.
For problem B we can say that the answer is YES if all components of black squares are rectangles. And then we can solve the problem by the hard way and do dfs.
For people who are getting WA on D, this case might be helpful:
Input
1
19208 14
Expected
YES
Thank you!!!
In D, for test case 128 4, why cant we partition it as 4*4*4*2 and 4*4*8 ?
Can anyone explain me the DP tutorial of question D.
Haha. I like the editorial solution of B. I myself spent a lot of time implementing B because I was dumb enough to do the straightforward method of checking if each connected component of 1s formed a rectangle.
Thank you for the quick editorial as well!
Please fix this
In $$$D$$$, a simple way to think about the case where $$$d=p^k$$$, $$$x=d^a\cdot b$$$, and $$$b=p^e\cdot f$$$, such that $$$p$$$ is prime, $$$k\geq 1$$$, $$$a\geq2$$$, $$$0\leq e<k$$$, and $$$f$$$ is not a multiple of $$$p$$$:
The maximum-length valid factorization has $$$a$$$ factors, which can be {$$$d$$$, $$$d$$$, ..., $$$d\cdot b$$$}, let's see if we can obtain a different valid factorization as well:
can problem F be done if the inter-section of the two subsequence need not be the whole array ?
How should one approach problems such as yesterday's D?
A copious amount of casework was required and it is very easy to either overlook or mess up one or more cases.
I can not understand Problem D. Madoka and the Best School in Russia.
How is the test case x=128 and d=4 giving the output 'NO'?
If we factorize 128 then some of the valid results are 8*16 and 32*4. Here all of them are good and 8(first case),4(second case) are both beautiful. I know I am missing something but I can not figure it out.
Both numbers need to be beautiful. 16 and 32 are not.
then what about the final test case "1000 10".How can it can output "YES" since all its beatiful factors are [10,20,40,50,250]?--->(it seems like there are only one set to get 1000(20,50))
you can use >=2 beautiful numbers to get x. So [10,10,10] and [20,50] both work.
Can someone Help me with what is wrong in my solution ?
https://mirror.codeforces.com/contest/1647/submission/149384795
I cannot find a case where this will fail. Thanks in advance.
Failing testcase: Ticket 1931
Can anyone tell me why I am getting TLE by using unbounded knapsack approach in problem D?
My submission
Got my mistake.
Anyone looking for dp solution for problem D can check out this — 149391053
Finding beautiful divisors — Let two good numbers be k1*d,k2*d. A number is beautiful iff it cannot be represented as product of two good numbers. This means that beautiful number != k1*k2*d^2. So, a beautiful number cannot be divisible by d^2. Check all divisors of x, if they satisfy x%d == 0 and x%(d^2) != 0 then divisor is beautiful.
Let dp[ i ][ j ] represent no of ways to form product j considering first i beautiful divisors. I used top down unbounded knapsack like approach since we can use any amount of good numbers to reach x. (similar to infinite supply of coins)
dp[ i ][ j ] = dp[ i-1 ][ j ] + dp[ i-1 ][j / beautiful [ i ] ];
Using relevant base cases and conditions, required ans = dp[n-1][x]. Since x is uptil 1e9 using conventional 2d array will result in MLE. So I used a map and replaced this memoization condition by map.find({i,j}) != map.end().
I tried a bottom up approach also but got a TLE and almost MLE — 149387702. If anyone has done bottom up please share submission link.
There is a nice a trick to replace the map $$$dp$$$ with a $$$2d$$$ array.
We know that the values that can appear in the second dimension are divisors of $$$x$$$. So, we can have an array $$$to\_id$$$ to map each divisor to an $$$ID$$$, obtain that $$$ID$$$ later in $$$O(1)$$$, and use it as an index in the $$$dp$$$ array's second dimension.
Since for each divisor $$$d$$$ either $$$d\le \sqrt{x}$$$ or $$$\dfrac{x}{d}\le \sqrt{x}$$$, if $$$d\le \sqrt{x}$$$, we can store $$$ID$$$ of $$$d$$$ directly in $$$to\_id[d]$$$, otherwise, we can store the $$$ID$$$ in $$$to\_id[\dfrac{x}{d}+\sqrt{x}]$$$. So, size of $$$to\_id$$$ is at most $$$~2\cdot \sqrt{x}$$$.
Thanks for this trick.Can You please show the implementation of this trick ?
Since my second state of dp is product / beautiful[ i ], how to use to_id map here ?
My submission.
Хотел немного пожаловаться на условия задачи. В задаче C было сказано, что верхний левый угол белый, также было сказано о перекрашивании. Может, я один неправильно понял, но мне кажется, бОльшая часть человек словило затуп на том, красим ли мы в белый цвет наш подпрямоугольник
A number is beautiful only if it is a multiple of d, but not a multiple of d^2
if a number is muntiple od d^2 then ofcourse it's devisible by d.
Maybe my English level is low,but what is the meaning of "expand the array" in the editorial of problem F?
In other words,why isn't it called "reverse the array" ?
Sorry to bother you to think about it. :(
Because someone has no better)))
It seems that first and third case in F can be done without dp. Take the first case as example, we can take out all prefix maximal element, then the dp value is the maximul in the rest. 149532612
I think there is a problem with the language in the explanation of problem D solution 2. In the explanation, checking that "a<=2" happens after we check that "d is composite and not a power of prime" (2nd to last paragraph). However, this means that we do not check whether a<=2 for the case "d is the power of a prime" (last paragraph). This means an implementation following this description fails on x=32 d=2 (outputs "YES" when the answer is "NO").
I found the explanation of Solution 1 of Problem D in editorial difficult to read, so I will write down my understanding.
The explanation of $$$dp[n][b]$$$ is as follows.
Take the case $$$(x, d) = (36, 2)$$$ for example. Since there are two ways $$$(2 * 18), (6 * 6)$$$, the answer to this case is "YES".
Since we want to represent $$$x = 36$$$ as a product of several beautiful numbers, let's find all beautiful numbers that is divisor of $$$x = 36$$$. In this case $$$(2, 6, 18)$$$.
Initialize with $$$dp[36][1] = 1$$$. In $$$dp[n][b]$$$ we always need to use one of $$$(2, 6, 18)$$$ to decompose $$$n$$$ once.
Note that transitions such as $$$dp[3][2] += dp[6][6]$$$, where the destination $$$b$$$ value is smaller, are prohibited by the definition of $$$dp$$$ (otherwise it would be overcounting).
As a result, we find two states in which $$$x = 36$$$ is completely decomposed: $$$dp[1][18], dp[1][6]$$$. And we see that they correspond to $$$(2 * 18), (6 * 6)$$$ (as mentioned above).
In other words, the state in which $$$x = 36$$$ is completely decomposed is denoted by $$$dp[1][b]$$$, and the sum of $$$dp[1][b]$$$ is the value we want. We can solve this problem by checking if this sum is greater than or equal to $$$2$$$.
Here is my C++ code (modified to make the editorial code more readable).
157492577
For problem D , I have a different approach of order(T*root(n)) (T is number of testcases.).I took 4 cases.When n=d^1,ans is NO. When n is of form=k*d^2,if divisors of k are greater than 1 then answer is yes else no.When n is of form k*d^m where m>3,Ans is yes if either divisors of k or divisors of d are greater then 2. Last case is n is of form k*d^m.If divisors of k>1,answer is YES.Else if k is prime no.,iterate through divisors of d and check if there exists a divisor such that k*divisor is not equal to d.If it exists then answer is YES else NO. The number of test cases may seem to be many but the coding implementation is simple. Here is a link to my solution : https://mirror.codeforces.com/contest/1647/submission/173842574