Processing math: 100%
(Analysis by Benjamin Qi)

Subtasks 1 and 2

As in the solution for the Bronze version of this problem, we can compute the number of cows checked for each possible operation and sum all of them. This takes O(N3) or O(N2) time.

Subtask 2 (Alternative)

Let's describe a different O(N2) time solution. This one can be optimized to solve the remaining subtasks.

Note: for consistency with the solution code, we assume both a and b are zero-indexed instead of one-indexed.

Let's iterate over all pairs (i,j) such that ai=bj and for each one, determine its contribution to the answer in O(1) time; that is the number of operations sending i to j. Without loss of generality, assume ij (to determine the contribution coming from i>j, we can reverse the array and apply the same computations).

#include <bits/stdc++.h>
using namespace std;

#define all(x) begin(x), end(x)
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define F0R(i, a) FOR(i, 0, a)

using ll = int64_t;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int N;
    cin >> N;
    vector<int> A(N), B(N);
    for (int &x : A) cin >> x;
    for (int &x : B) cin >> x;
    auto ways2 = [&](ll x) { return x * (x + 1) / 2; };
    ll ans = 0;
    F0R(i, N) if (A[i] == B[i]) {
        ans += ways2(i) + ways2(N - 1 - i) + min(i, N - 1 - i) + 1;
    }
    F0R(_, 2) {
        F0R(i, N)
        FOR(j, i + 1, N) if (A[i] == B[j]) ans += min(i, N - 1 - j) + 1;
        reverse(all(A));
        reverse(all(B));
    }
    cout << ans << "\n";
}

Subtask 3

For the remaining subtasks, the only part we need to speed up is the computation of the contribution from i<j. The logic for i=j will remain the same.

When all values are generated independently and uniformly at random from the range [1,N], we can observe that the expected number of pairs satisfying ai=bj is only N (there are N2 pairs (i,j), and each one satisfies ai=bj with probability 1/N). So as long as our solution takes time proportional to N plus the number of equal pairs, it will likely be fast enough for this subtask.

In the code below we initialize lists for each species value v from 1N, then for each v we iterate over all ways to select a position from a and a position from b with species v.

#include <bits/stdc++.h>
using namespace std;

#define all(x) begin(x), end(x)
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define F0R(i, a) FOR(i, 0, a)

using ll = int64_t;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int N;
    cin >> N;
    vector<int> A(N), B(N);
    for (int &x : A) cin >> x;
    for (int &x : B) cin >> x;
    auto ways2 = [&](ll x) { return x * (x + 1) / 2; };
    ll ans = 0;
    F0R(i, N) if (A[i] == B[i]) {
        ans += ways2(i) + ways2(N - 1 - i) + min(i, N - 1 - i) + 1;
    }
    F0R(_, 2) {
        vector<vector<int>> with_A(N + 1), with_B(N + 1);
        F0R(i, N) with_A[A[i]].push_back(i), with_B[B[i]].push_back(i);
        FOR(v, 1, N + 1) {
            for (int i : with_A[v])
                for (int j : with_B[v])
                    if (i < j) ans += min(i, N - 1 - j) + 1;
        }
        reverse(all(A));
        reverse(all(B));
    }
    cout << ans << "\n";
}

Full Solution

For full credit, let's process each value v in time proportional to the number of times it appears in a or b. Summing over all values will give a solution running in O(N) time.

There are two types of contributions depending on whether Nj is "big" or "small" relative to i+1:

If i is fixed, a suffix of j have small contributions, and the remaining j have big contributions.

Let's iterate over the occurrences of v from right to left; when we encounter an occurrence of bj=v let's record it, and when we encounter an occurrence of ai=v let's add its contribution with all occurrences of v in b recorded so far to the answer.

Each Nj initially starts out with a "small" contribution but changes to a "big" contribution when i gets small enough. Thus, we store the following information about j seen so far:

When we encounter bj=v we add to the sum of the small contributions and push Nj to the stack. When we encounter ai=v we pop from the stack as necessary; every time we pop from the stack we subtract from the sum and add to the number of big contributions.

#include <bits/stdc++.h>
using namespace std;
 
#define all(x) begin(x), end(x)
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define F0R(i, a) FOR(i, 0, a)
 
using ll = int64_t;
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int N;
    cin >> N;
    vector<int> A(N), B(N);
    for (int &x : A) cin >> x;
    for (int &x : B) cin >> x;
    auto ways2 = [&](ll x) { return x * (x + 1) / 2; };
    ll ans = 0;
    F0R(i, N) if (A[i] == B[i]) {
        ans += ways2(i) + ways2(N - 1 - i) + min(i, N - 1 - i) + 1;
    }
    F0R(_, 2) {
        vector<vector<pair<int, int>>> with_oc(N + 1);
        F0R(i, N) {
            with_oc.at(B.at(i)).push_back({i, 1});
            with_oc.at(A.at(i)).push_back({i, 0});
        }
        FOR(v, 1, N + 1) {
            reverse(all(with_oc.at(v)));
            stack<int> stk;
            int num_large = 0;
            ll sum_small = 0;
            auto query = [&](int x) {
                while (!stk.empty() && stk.top() > x) {
                    ++num_large;
                    sum_small -= stk.top();
                    stk.pop();
                }
                return sum_small + (ll)num_large * x;
            };
            for (auto [idx, which] : with_oc.at(v)) {
                if (which == 0) {
                    ans += query(idx + 1);
                } else {
                    int v = N - idx;
                    sum_small += v;
                    stk.push(v);
                }
            }
        }
        reverse(all(A));
        reverse(all(B));
    }
    cout << ans << "\n";
}

Subtask 4

This subtask was intended to give credit for solutions that process each value v that occurs in a and b in O(N) time (e.g., using prefix sums to handle the "big" and "small" contributions mentioned above). The details are omitted.