C - 暗号変換と補正 / Cipher Conversion and Correction 解説 by admin
gpt-5.3-codexOverview
For each split position \(k\), we determine whether a “non-negative, non-increasing” correction sequence \(D\) can bring all elements of the transformed value sequence \(A\) into the lowercase letter range \([97,122]\), and count the number of valid \(k\) values.
This can be solved by precomputing XOR values and greedily checking the allowable interval at each position.
Analysis
First, let’s organize what is determined when we fix a split position \(k\).
- Left half XOR: \(X_L = s_1 \oplus \cdots \oplus s_k\)
- Right half XOR: \(X_R = s_{k+1} \oplus \cdots \oplus s_N\)
The transformed value \(A_i\) for each character is: - If \(i \le k\): \(A_i = s_i \oplus X_R\) - If \(i > k\): \(A_i = s_i \oplus X_L\)
The conditions on the correction sequence \(D\) are: 1. \(D_i \ge 0\) 2. \(D_1 \ge D_2 \ge \cdots \ge D_N\) 3. \(97 \le A_i + D_i \le 122\)
Looking at position \(i\) alone, \(D_i\) must be in the following range:
[ \max(0,\,97-A_i) \le D_i \le 122-A_i ]
Defining: - Lower bound \(L_i = \max(0,97-A_i)\) - Upper bound \(U_i = 122-A_i\)
The problem becomes: for each \(i\), “\(D_i \in [L_i,U_i]\)” while maintaining a non-increasing sequence overall.
Issues with the Naive Approach
- Computing \(X_L, X_R\) by scanning forward and backward for each \(k\) takes \(O(N)\), and the validity check also takes \(O(N)\), giving a total of \(O(N^2)\). However, redundantly recomputing XOR values increases the constant factor.
- Searching for \(D\) exploratively (backtracking, etc.) is of course too slow.
Key Observations
XOR can be computed instantly using prefix sums
With a prefix XOR array: [ X_L = \text{pref}[k],\quad X_R = \text{pref}[N]\oplus \text{pref}[k] ] in \(O(1)\).The \(D\) validity check can be done greedily
Process from left to right, maintainingcur(the maximum value available for the next choice) based on previously chosen values.
Due to the non-increasing condition, the next \(D_i\) must be at mostcur.
Additionally, it must fall within the interval \([L_i,U_i]\), so:- First, reflect the upper bound:
cur = min(cur, U_i) - If
cur < L_i, it’s impossible - Otherwise, we can set \(D_i = cur\)
- First, reflect the upper bound:
“Always taking the largest possible value” is optimal because it gives subsequent positions the most flexibility (making it too small increases the chance of failure later), so this greedy approach is correct.
Algorithm
- Build the prefix XOR array
preffor string \(S\). - Compute the total XOR:
totalXor = pref[N]. - For each split position \(k=1..N-1\):
- Compute \(X_L = pref[k]\), \(X_R = totalXor \oplus X_L\).
- Start with
cur = 122(maximum candidate for \(D_1\)). - Process \(i=0..N-1\) in order:
- Compute \(A_i\) (if in the first half:
S[i]^XR, if in the second half:S[i]^XL) - \(L=\max(0,97-A_i)\), \(U=122-A_i\)
- If \(U<0\), immediately impossible (even with \(D_i\ge0\), the upper bound cannot be satisfied)
cur = min(cur, U)- If
cur < L, impossible
- Compute \(A_i\) (if in the first half:
- If we process all positions successfully, this \(k\) is a valid split position.
- Output the number of valid split positions.
Complexity
- Time complexity: \(O(N^2)\)
- Space complexity: \(O(N)\)
Implementation Notes
In C++,
S[i]is achar, so explicitly casting to(int)S[i]when performing XOR is safer.currepresents “the maximum value currently achievable while satisfying all conditions so far.” The update order should be:
- Narrow by upper bound:
cur=min(cur,U)
- Check lower bound:
cur<L
This order is the clearest.
- Narrow by upper bound:
Per the problem constraints, \(k\) is iterated from
1toN-1.Source Code
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
string S;
cin >> N >> S;
vector<int> pref(N + 1, 0);
for (int i = 0; i < N; i++) {
pref[i + 1] = pref[i] ^ (int)S[i];
}
int totalXor = pref[N];
int good = 0;
for (int k = 1; k <= N - 1; k++) {
int XL = pref[k];
int XR = totalXor ^ XL;
int cur = 122; // maximal allowed D_1 due to upper bound
bool ok = true;
for (int i = 0; i < N; i++) {
int c = (int)S[i];
int A = (i < k) ? (c ^ XR) : (c ^ XL);
int L = max(0, 97 - A);
int U = 122 - A;
if (U < 0) { // impossible even with D_i >= 0
ok = false;
break;
}
if (cur > U) cur = U; // enforce D_i <= U and non-increasing from previous
if (cur < L) { // no feasible D_i
ok = false;
break;
}
// choose D_i = cur (max feasible) to keep future flexibility
}
if (ok) good++;
}
cout << good << '\n';
return 0;
}
This editorial was generated by gpt-5.3-codex.
投稿日時:
最終更新: