The problem of finding the minimal string obtained by XORing a binary string with all possible values can be approached using suffix sorting techniques. Each XOR operation with (2^k) swaps adjacent blocks of length (2^k), and any XOR value is a composition of such transformations.
Define arrays (sa_{k,x}) and (rk_{k,x}) representing the sorted order of prefixes of length (2^k) for strings formed by XORing with value (x). The prefix of length (2^{k+1}) is formed by concatenating two such prefixes. This leads to a suffix sorting adaptation where (rk[i+w]) becomes (rk[i \oplus w]).
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
int main() {
int n;
cin >> n;
string str;
cin >> str;
int size = 1 << n;
vector<int> bucket(27, 0), suffixArray(size), rank(size), tempRank(size), order(size);
for (int i = 0; i < size; ++i) {
rank[i] = str[i] - 'a' + 1;
bucket[rank[i]]++;
}
for (int i = 1; i <= 26; ++i) bucket[i] += bucket[i - 1];
for (int i = size - 1; i >= 0; --i) suffixArray[--bucket[rank[i]]] = i;
int distinct = 26;
for (int step = 1; step <= size; step <<= 1) {
fill(bucket.begin(), bucket.begin() + distinct + 1, 0);
for (int i = 0; i < size; ++i) bucket[rank[suffixArray[i] ^ step]]++;
for (int i = 1; i <= distinct; ++i) bucket[i] += bucket[i - 1];
for (int i = size - 1; i >= 0; --i) order[--bucket[rank[suffixArray[i] ^ step]]] = suffixArray[i];
fill(bucket.begin(), bucket.begin() + distinct + 1, 0);
for (int i = 0; i < size; ++i) bucket[rank[order[i]]]++;
for (int i = 1; i <= distinct; ++i) bucket[i] += bucket[i - 1];
for (int i = size - 1; i >= 0; --i) suffixArray[--bucket[rank[order[i]]]] = order[i];
tempRank = rank;
rank[suffixArray[0]] = 1;
distinct = 1;
for (int i = 1; i < size; ++i) {
int curr = suffixArray[i], prev = suffixArray[i - 1];
if (tempRank[curr] == tempRank[prev] && tempRank[curr ^ step] == tempRank[prev ^ step]) {
rank[curr] = distinct;
} else {
rank[curr] = ++distinct;
}
}
if (distinct == size) break;
}
for (int i = 0; i < size; ++i) cout << str[i ^ suffixArray[0]];
cout << endl;
return 0;
}
For the Snowy Mountain problem, consider a path of length (L) ending at a basin. Define height (h_x) via multi-source BFS from basins. The kinetic energy dynamics show that after (h_x) steps increasing energy and (L - h_x) steps decreasing it, the remaining energy is (2h_x - L).
A greedy strategy involves tarversing edges where (h_u = h_v). If kinetic energy remains when crossing such an edge, oscillating along it can extend the path until energy depletes. This leads to an energy remainder (w = h_u = h_v), giving (L = 2h_x - w). The objective is to minimize (w) for each starting point (x), where (w) is the minimal value among reachable nodes with an edge satisfying (h_u = h_v).
Let (S = {u \mid \exists (u,v) \in E, h_u = h_v}). The sum (\sum_{u \in S} h_u) is (O(n)), implying the number of distinct (h_u) values in (S) is (O(\sqrt{n})). This reduces the state space.
Define (dp_{u,i}) as the negative of the minimum kinetic energy (allowing negative values) on any path from (u) to a node with height (i), where (i) ranges over (O(\sqrt{n})) distinct heights. Transitions require handling nodes with equal heights separately, which are disjoint connected components. Perform upward and downward dynamic progarmming within each component to compute values correctly.
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
using namespace std;
const int MAX_N = 200005;
const int INF = INT_MAX / 2;
vector<int> graph[MAX_N];
vector<int> heightGroups[MAX_N];
int height[MAX_N];
int compId[MAX_N];
int dp[MAX_N][500];
int distinctHeights[500];
int heightIndex[MAX_N];
bool visited[MAX_N];
int totalHeights = 0;
void minimize(int &a, int b) { if (b < a) a = b; }
void maximize(int &a, int b) { if (b > a) a = b; }
void processUpward(int node, int parent, int currentHeight) {
visited[node] = true;
for (int neighbor : graph[node]) {
if (neighbor == parent || height[neighbor] != currentHeight) continue;
processUpward(neighbor, node, currentHeight);
for (int idx = 1; idx <= totalHeights; ++idx) {
minimize(dp[node][idx], dp[neighbor][idx] + 1);
}
dp[node][heightIndex[currentHeight]] = 1;
}
}
void processDownward(int node, int parent, int currentHeight) {
for (int neighbor : graph[node]) {
if (neighbor == parent || height[neighbor] != currentHeight) continue;
for (int idx = 1; idx <= totalHeights; ++idx) {
minimize(dp[neighbor][idx], dp[node][idx] + 1);
}
dp[neighbor][heightIndex[currentHeight]] = 1;
processDownward(neighbor, node, currentHeight);
}
}
int main() {
int n;
cin >> n;
vector<int> basins;
for (int i = 1; i <= n; ++i) {
int isBasin;
cin >> isBasin;
if (isBasin) {
basins.push_back(i);
height[i] = 0;
} else {
height[i] = INF;
}
}
for (int i = 0; i < n - 1; ++i) {
int u, v;
cin >> u >> v;
graph[u].push_back(v);
graph[v].push_back(u);
}
queue<int> bfsQueue;
for (int basin : basins) {
bfsQueue.push(basin);
visited[basin] = true;
}
while (!bfsQueue.empty()) {
int current = bfsQueue.front();
bfsQueue.pop();
for (int neighbor : graph[current]) {
if (!visited[neighbor]) {
height[neighbor] = height[current] + 1;
visited[neighbor] = true;
bfsQueue.push(neighbor);
}
}
}
fill(visited, visited + n + 1, false);
for (int node = 1; node <= n; ++node) {
heightGroups[height[node]].push_back(node);
if (heightIndex[height[node]]) continue;
for (int neighbor : graph[node]) {
if (height[node] == height[neighbor]) {
distinctHeights[++totalHeights] = height[node];
heightIndex[height[node]] = totalHeights;
break;
}
}
}
for (int h = 0; h <= n; ++h) {
for (int node : heightGroups[h]) {
for (int idx = 1; idx <= totalHeights; ++idx) dp[node][idx] = INF;
for (int neighbor : graph[node]) {
if (height[neighbor] != h - 1) continue;
for (int idx = 1; idx <= totalHeights; ++idx) {
if (dp[neighbor][idx]) minimize(dp[node][idx], dp[neighbor][idx] - 1);
else dp[node][idx] = 0;
}
}
}
for (int node : heightGroups[h]) {
if (!visited[node]) {
processUpward(node, 0, h);
processDownward(node, 0, h);
}
}
}
for (int node = 1; node <= n; ++node) {
int best = height[node];
for (int idx = 1; idx <= totalHeights; ++idx) {
if (dp[node][idx] == 0) maximize(best, 2 * height[node] - distinctHeights[idx]);
}
cout << best << " ";
}
cout << endl;
return 0;
}