Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
For one person, forget the whole watched set. It is always a prefix . So the only episode that can be watched next is .
If both currently need episode , a day is dangerous only if at least one of equals . Values smaller or larger than are just noise for that moment.
For each episode , make an ordered list of days where appears. A day with is a good event; a day with exactly one side equal to is a bad event. If , that day is bad for both listed values.
After a good event for episode at day , the next state is completely determined by the first event of episode after . So define as the first future bad day from there.
Compute those values for good events by decreasing episode number. Then for each left endpoint , binary-search the first event of episode with position ; if it is bad, it kills the segment there, otherwise jump to its precomputed .
For one person, the set of watched episodes is always a prefix. If they have watched , then on a day with value they watch exactly when .
So while Alice and Bob have the same next needed episode , a day is legal iff either both values are , or neither value is .
A valid segment never lets their progress differ. Starting equal, they either both advance by watching episode , or both do nothing.
Fix a moment just after day , and suppose the next needed episode is . Every future day that does not contain is pure noise. The first future day containing decides everything:
If no such exists, nothing bad can ever happen. If , they both watch episode and the state becomes after day . Otherwise exactly one side sees episode , and the segment dies at . Brutal, but convenient.
For each episode , store all days where appears in either schedule. Mark a stored day as:
If , the same day is a bad event for both values and .
For a good event at day for episode , define as the first bad day after they have just watched episode on day . Equivalently, the next needed episode is after .
To compute it, look in the event list of episode for the first event after :
This is why we process episodes in decreasing order: when computing episode , all dp values for good events of episode are already known. No magic, just refusing to do the same simulation times.
For a left endpoint , the first relevant event is the first event of episode at day .
Let this first invalid day be , using if there is none. Then exactly
segments start at . Sum this over all .
Each event list is binary-searched a constant number of times. There are at most stored events, so the complexity per test case is
with memory. The constraints are fine; no need for a cursed quadratic simulator.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> a(n + 1), b(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) cin >> b[i];
vector<vector<int>> pos(n + 2);
vector<vector<char>> good(n + 2);
auto add_event = [&](int x, int p, char is_good) {
pos[x].push_back(p);
good[x].push_back(is_good);
};
for (int i = 1; i <= n; i++) {
if (a[i] == b[i]) {
add_event(a[i], i, 1);
} else {
add_event(a[i], i, 0);
add_event(b[i], i, 0);
}
}
vector<int> dp(n + 2, n + 1);
for (int x = n; x >= 1; x--) {
for (int id = 0; id < (int)pos[x].size(); id++) {
if (!good[x][id]) continue;
int p = pos[x][id];
if (x == n) {
dp[p] = n + 1;
continue;
}
auto it = upper_bound(pos[x + 1].begin(), pos[x + 1].end(), p);
if (it == pos[x + 1].end()) {
dp[p] = n + 1;
continue;
}
int j = int(it - pos[x + 1].begin());
int q = *it;
dp[p] = good[x + 1][j] ? dp[q] : q;
}
}
ll ans = 0;
for (int L = 1; L <= n; L++) {
auto it = lower_bound(pos[1].begin(), pos[1].end(), L);
int bad;
if (it == pos[1].end()) {
bad = n + 1;
} else {
int j = int(it - pos[1].begin());
int q = *it;
bad = good[1][j] ? dp[q] : q;
}
ans += bad - L;
}
cout << ans << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> a(n + 1), b(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) cin >> b[i];
vector<vector<int>> pos(n + 2);
vector<vector<char>> good(n + 2);
auto add_event = [&](int x, int p, char is_good) {
pos[x].push_back(p);
good[x].push_back(is_good);
};
for (int i = 1; i <= n; i++) {
if (a[i] == b[i]) {
add_event(a[i], i, 1);
} else {
add_event(a[i], i, 0);
add_event(b[i], i, 0);
}
}
vector<int> dp(n + 2, n + 1);
for (int x = n; x >= 1; x--) {
for (int id = 0; id < (int)pos[x].size(); id++) {
if (!good[x][id]) continue;
int p = pos[x][id];
if (x == n) {
dp[p] = n + 1;
continue;
}
auto it = upper_bound(pos[x + 1].begin(), pos[x + 1].end(), p);
if (it == pos[x + 1].end()) {
dp[p] = n + 1;
continue;
}
int j = int(it - pos[x + 1].begin());
int q = *it;
dp[p] = good[x + 1][j] ? dp[q] : q;
}
}
ll ans = 0;
for (int L = 1; L <= n; L++) {
auto it = lower_bound(pos[1].begin(), pos[1].end(), L);
int bad;
if (it == pos[1].end()) {
bad = n + 1;
} else {
int j = int(it - pos[1].begin());
int q = *it;
bad = good[1][j] ? dp[q] : q;
}
ans += bad - L;
}
cout << ans << '\n';
}
return 0;
}