C. The Ancient Wizards' Capes
Problem Statement
There are wizards in a row, numbered 1 to from left to right. Each wizard has an invisibility cape that can be worn on either their left or right side.
Harry walks from the position of wizard 1 to the position of wizard (). At each wizard’s position , he records the total number of wizards he can see.
A wizard at position is visible from position if:
- Wizard wears their cape on their left side, and .
- Wizard wears their cape on their right side, and .
Note that wizard is always visible from their own position, .
You have deciphered Harry’s old list, which is an array of elements. The -th element, (), is the number of wizards Harry saw from position .
Your task is to determine how many of all possible cape arrangements are consistent with the data in list .
Solution Explanation
The core of this problem lies in understanding the relationship between the number of visible wizards at adjacent positions, and . This relationship will reveal the relative orientation of the capes of wizard and wizard .
Let’s denote if wizard wears their cape on the left, and if they wear it on the right.
According to the problem definition, the number of wizards visible from position , , is the sum of:
- Wizards with capes on their left side.
- Wizards with capes on their right side.
This can be formulated as:
Now, let’s write the same formula for position :
Let’s find the difference, :
The first part simplifies to . The second part simplifies to . So, the relationship is:
Rearranging this gives us:
This equation tells us that the sum of the cape orientations for two adjacent wizards ( and ) is determined by the difference in their visibility counts (). Let’s analyze the possible cases for the difference :
- : . Since can only be 0 or 1, this means and . Both wizards wear their capes on the left.
- : . This means and . Both wizards wear their capes on the right.
- : . This means one wizard has a left cape (1) and the other has a right cape (0). Their capes are in opposite directions.
This observation is key: the relative orientation of cape to cape is uniquely determined. If we know the orientation of the first wizard’s cape, we can determine the orientation for all subsequent wizards one by one.
This leaves only two possible valid arrangements for the entire row of wizards:
- One arrangement starting with wizard 1’s cape on the left.
- One arrangement starting with wizard 1’s cape on the right.
Our algorithm is as follows:
- Test the first possibility: Assume wizard 1 has a left cape.
- Iterate from to , using the relationship derived above to determine the cape orientation for wizard based on , , and the now-known orientation of wizard .
- After determining the full arrangement, we must verify it. Calculate the visibility array
visfrom scratch based on this arrangement and check ifvis[i] == a[i]for all . - If the arrangement is valid, we count it as one solution.
- Test the second possibility: Repeat the process, this time assuming wizard 1 has a right cape.
- If this second arrangement is valid, we add it to our count.
- The final answer is the total count, which can be 0, 1, or 2.
View Code
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <iostream>
#include <map>
#include <numeric>
#include <set>
#include <tuple>
#include <vector>
using namespace std;
#define int long long
// #define mod 1000000007
#define N 500005
void solve() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
vector<bool> a_side(n, false); // false; visibile from left
for (int i = 1; i < n; i++) {
if (a[i] == a[i - 1]) {
a_side[i] = !a_side[i - 1];
} else {
a_side[i] = a_side[i - 1];
}
}
auto func_verify = [&](vector<int> &a, vector<bool> &a_side) -> bool {
int vis_t = 0;
vector<int> vis(n, 0);
for (int i = 0; i < n; i++) {
vis[i] += vis_t;
vis_t += a_side[i] == false ? 1 : 0;
}
vis_t = 0;
for (int i = n - 1; i >= 0; i--) {
vis[i] += vis_t;
vis_t += a_side[i] == true ? 1 : 0;
}
// if vis == a, return true
for (int i = 0; i < n; i++) {
if (vis[i]+1 != a[i]) {
return false;
}
}
return true;
};
int ans = func_verify(a, a_side) ? 1 : 0;
a_side[0] = true;
for (int i = 1; i < n; i++) {
if (a[i] == a[i - 1]) {
a_side[i] = !a_side[i - 1];
} else {
a_side[i] = a_side[i - 1];
}
}
ans += func_verify(a, a_side) ? 1 : 0;
cout << ans << endl;
}
int32_t main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
#ifdef DEBUG
freopen("./input.txt", "r", stdin);
#endif
int t;
cin >> t;
while (t--) {
#ifdef DEBUG
static int test_num = 1;
cout << "test case: " << test_num++ << endl;
#endif
solve();
}
}