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 i≤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 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 1…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 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 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 bj=v we add to the sum of the small contributions and push N−j 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"; }