1466B - Last Minute Enhancements

From start to end, increase element if it has already been encountered before (remember elements are given in non-decreasing order). Then, count unique elements.

Time complexity: $O(n)$

Memory complexity: $O(n)$

Click to show code.


using namespace std;
using ll = long long;
using ii = pair<int, int>;
using vi = vector<int>;
int solve(vi a)
{
    int n = (int)(a).size();
    vector<bool> vis(a.back() + 5, false);
    for (int i = 0; i < n; ++i)
    {
        if (vis[a[i]])
            a[i]++;
        vis[a[i]] = true;
    }
    return distance(begin(a), unique(begin(a), end(a)));
}
int main(void)
{
    ios::sync_with_stdio(false), cin.tie(NULL);
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        vi a(n);
        for (auto &x : a)
            cin >> x;
        cout << solve(a) << endl;
    }
    return 0;
}


1466A - Bovine Dilemma

In the formula $A = \frac{h_b b}{2}$, the only variable that changes is the base length, $b$. List all pairs, of points on the x axis and count the unique distances.

Time complexity: $O(n^2)$

Memory complexity: $O(n)$

Click to show code.


using namespace std;
using ll = long long;
using ii = pair<int, int>;
using vi = vector<int>;
int solve(vi a)
{
    int n = (int)(a).size(), ans = 0;
    vector<bool> vis(100, 0);
    for (int i = 0; i < n - 1; ++i)
    {
        for (int j = i + 1; j < n; ++j)
        {
            int b = abs(a[i] - a[j]);
            if (vis[b])
                continue;
            vis[b] = true;
            ans++;
        }
    }
    return ans;
}
int main(void)
{
    ios::sync_with_stdio(false), cin.tie(NULL);
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        vi a(n);
        for (auto &x : a)
            cin >> x;
        cout << solve(a) << endl;
    }
    return 0;
}


1362A - Johny And Ancient Computer

Without loss of generality, say $a \geq b$. We’ll try to make $b$ into $a$ by multiplying it by $2$, $4$ and $8$.

Note that this is only possible if $a = b \times 2^k$, for some integer $k$. We verify that, and then decompose $2^k$ into $8$s, $4$s and $2$s.

Time complexity: $O(\log{\max(a, b)})$

Memory complexity: $O(1)$

Click to show code.


using namespace std;
using ll = long long;
using ii = pair<int, int>;
using vi = vector<int>;
int solve(ll a, ll b)
{
    if (a % b)
        return -1;
    ll twok = a / b;
    int k = 0;
    while (twok != 1)
    {
        if (twok % 2)
            return -1;
        twok /= 2;
        k++;
    }
    int ans = 0;
    ans += k / 3;
    k %= 3;
    ans += k / 2;
    k %= 2;
    ans += k / 1;
    return ans;
}
int main(void)
{
    ios::sync_with_stdio(false), cin.tie(NULL);
    int t;
    cin >> t;
    while (t--)
    {
        ll a, b;
        cin >> a >> b;
        if (a < b)
            swap(a, b);
        cout << solve(a, b) << endl;
    }
    return 0;
}


990D - Graph And Its Complement

Editorial.

Time complexity: $O(n^2)$

Memory complexity: $O(n^2)$

Click to show code.


using namespace std;
using ll = long long;
using ii = pair<int, int>;
using vi = vector<int>;
pair<bool, vector<vi>> solve(int n, int a, int b)
{
    if (min(a, b) != 1 or (a == b and (n == 2 or n == 3)))
        return {false, {}};
    vector<vi> ans(n, vi(n, 0));
    bool rev = false;
    if (a < b)
    {
        rev = true;
        swap(a, b);
    }
    for (int i = 0; i < n - a; ++i)
        ans[i][i + 1] = ans[i + 1][i] = 1;
    if (rev)
    {
        for (int i = 0; i < n; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                if (i == j)
                    continue;
                ans[i][j] = 1 - ans[i][j];
            }
        }
    }
    return {true, ans};
}
int main(void)
{
    ios::sync_with_stdio(false), cin.tie(NULL);
    int n, a, b;
    cin >> n >> a >> b;
    if (auto [flag, mat] = solve(n, a, b); flag)
    {
        cout << "YES" << endl;
        for (auto row : mat)
        {
            for (auto x : row)
                cout << x;
            cout << endl;
        }
    }
    else
        cout << "NO" << endl;
    return 0;
}


402C - Searching For Graph

So, intuitively, we want edges to be uniformly distributed on the vertices, as to minimize the maximum edges for each subgraph in the hope that it fits the problem’s constraints.

One way to do so is to add edges in lexicographical order.

Time complexity: $O(n)$

Memory complexity: $O(1)$

Click to show code.


using namespace std;
int main(void)
{
    ios::sync_with_stdio(false), cin.tie(NULL);
    int t;
    cin >> t;
    while (t--)
    {
        int n, p, m;
        cin >> n >> p;
        m = 2 * n + p;
        for (int u = 1; u < n; ++u)
        {
            for (int v = u + 1; v <= n; ++v)
            {
                if (!m)
                    break;
                cout << u << " " << v << endl;
                m--;
            }
            if (!m)
                break;
        }
    }
    return 0;
}


279B - Books

We need to find a pair of indices [l, r] such that the sum of the book times in this interval is less than $t$ and is maximal.

We may fix the left border, $l$, and use binary search or a two pointers approach to find $r$.

Time complexity: $O(n)$

Memory complexity: $O(n)$

Click to show code.


using namespace std;
using ll = long long;
using ii = pair<int, int>;
using vi = vector<int>;
int solve(vi a, int t)
{
    int n = (int)(a).size(), r = 0, ans = 0;
    vi pa(n);
    partial_sum(begin(a), end(a), begin(pa));
    auto sum = [pa](int l, int r) { return pa[r] - (l == 0 ? 0 : pa[l - 1]); };
    for (int l = 0; l < n; ++l)
    {
        while (r < n and sum(l, r) <= t)
            ++r;
        ans = max(ans, r - l);
    }
    return ans;
}
int main(void)
{
    ios::sync_with_stdio(false), cin.tie(NULL);
    int n, t;
    cin >> n >> t;
    vi a(n);
    for (auto &x : a)
        cin >> x;
    cout << solve(a, t) << endl;
    return 0;
}


546A - Soldier And Bananas

Reduce summation to closed form and solve the equation.

Time complexity: $O(1)$

Memory complexity: $O(1)$

Click to show code.


using namespace std;
using ll = long long;
using ii = pair<int, int>;
using vi = vector<int>;
int main(void)
{
    ios::sync_with_stdio(false), cin.tie(NULL);
    int k, n, w;
    cin >> k >> n >> w;
    int x = max(k * (w * (w + 1)) / 2 - n, 0);
    cout << x << endl;
    return 0;
}


1469C - Building A Fence

Intuitively, the position with highest ground level constraints its neighbors. We build on top of this idea.

We’ll maintain a priority queue or set where each position is ordered based on their ground level height, decreasingly.

The idea is that, we start from the highest ground level, update its neighbors heights so that they minimally share a side with it, mark it as done and continue with the next highest position. If at any step we can’t perform an update on the neighbors (as it would exceed the $k - 1$ displacement from their ground level), then it’s impossible.

Since we’re updating from top to bottom and updating the neighbor’s height to minimally share a side, we’ll never place a fence too far down (or if we do, then it’s fixable. I’m lazy today, so I’ll skip the proof.).

Time complexity: $O(n \log{n})$

Memory complexity: $O(n)$

Click to show code.


using namespace std;
using ll = long long;
using ii = pair<int, int>;
using vi = vector<int>;
bool solve(vi h, int k)
{
    int n = (int)(h).size();
    set<ii, greater<ii>> hordered;
    for (int i = 0; i < n; ++i)
        hordered.emplace(h[i], i);
    vector<bool> visited(n, false);
    for (int j = 0; j < n; ++j)
    {
        auto cur = hordered.begin();
        auto [hi, i] = *cur;
        if (i - 1 >= 0 and not visited[i - 1])
        {
            int hmax = h[i - 1] + (i - 1 == 0 ? k - 1 : 2 * k - 2);
            if (h[i] > hmax)
                return false;
            auto it = hordered.find(ii{h[i - 1], i - 1});
            h[i - 1] = max(hi - k + 1, h[i - 1]);
            hordered.erase(it);
            hordered.emplace(h[i - 1], i - 1);
        }
        if (i + 1 < n and not visited[i + 1])
        {
            int hmax = h[i + 1] + (i + 1 == n - 1 ? k - 1 : 2 * k - 2);
            if (h[i] > hmax)
                return false;
            auto it = hordered.find(ii{h[i + 1], i + 1});
            h[i + 1] = max(h[i] - k + 1, h[i + 1]);
            hordered.erase(it);
            hordered.emplace(h[i + 1], i + 1);
        }
        visited[i] = true;
        hordered.erase(cur);
    }
    return true;
}
int main(void)
{
    ios::sync_with_stdio(false), cin.tie(NULL);
    int t;
    cin >> t;
    while (t--)
    {
        int n, k;
        cin >> n >> k;
        vi h(n);
        for (auto &x : h)
            cin >> x;
        cout << (solve(h, k) ? "YES" : "NO") << endl;
    }
    return 0;
}


1469B - Red And Blue

$f(a)$ is maximized when $a$ is of the form:

a = r[0, i] . b[0, j] . r[i + 1, n] . b[j + 1, m]

Where . means concatenation and $i$ and $j$ are the indices that maximize their respective prefix sums.

The reason behind is that the sum of a[0... i + j] = r[0, i] . b[0, j] will be a consequently the maximal term of $f(a)$ for all $a$.

Time complexity: $O(n)$

Memory complexity: $O(n)$

Click to show code.


using namespace std;
using ll = long long;
using ii = pair<int, int>;
using vi = vector<int>;
int solve(vi r, vi b)
{
    int n = (int)(r).size(), m = (int)(b).size();
    vi pr(n, 0), pb(m, 0);
    partial_sum(begin(r), end(r), begin(pr));
    partial_sum(begin(b), end(b), begin(pb));
    return max(*max_element(begin(pr), end(pr)), 0) + max(*max_element(begin(pb), end(pb)), 0);
}
int main(void)
{
    ios::sync_with_stdio(false), cin.tie(NULL);
    int t;
    cin >> t;
    while (t--)
    {
        int n, m;
        cin >> n;
        vi r(n);
        for (auto &x : r)
            cin >> x;
        cin >> m;
        vi b(m);
        for (auto &x : b)
            cin >> x;
        cout << solve(r, b) << endl;
    }
    return 0;
}


1469A - Regular Bracket Sequence

There are two cases in which it is impossible to construct a valid sequence:

  1. The length of the sequence is odd.
  2. A parenthesis is unmatchable: ).... or ....(.

To understand why is it otherwise always possible, let $t$ be the string that results from greedy-matching the existing parenthesis (matching a parenthesis with the closest interrogation symbol). Such a string will be empty or be an even-length sequence of ?, which is trivially regular (first half ( and second half )).

Time complexity: $O(1)$

Memory complexity: $O(n)$

Click to show code.


using namespace std;
using ll = long long;
using ii = pair<int, int>;
using vi = vector<int>;
bool solve(string s)
{
    if (s[0] == ')' or s.back() == '(')
        return false;
    return ((int)(s).size() - 2) % 2 == 0;
}
int main(void)
{
    ios::sync_with_stdio(false), cin.tie(NULL);
    int t;
    cin >> t;
    while (t--)
    {
        string s;
        cin >> s;
        cout << (solve(s) ? "YES" : "NO") << endl;
    }
    return 0;
}