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 $a_i=b_j$ 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 $i\le j$ (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"; }
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 $a_i=b_j$ is only $N$ (there are $N^2$ pairs $(i,j)$, and each one satisfies $a_i=b_j$ 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 $1\dots N$, 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"; }
There are two types of contributions depending on whether $N-j$ 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 $b_j=v$ let's record it, and when we encounter an occurrence of $a_i=v$ let's add its contribution with all occurrences of $v$ in $b$ recorded so far to the answer.
Each $N-j$ 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 $b_j=v$ we add to the sum of the small contributions and push $N-j$ to the stack. When we encounter $a_i=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"; }