Problem
Given a string and a pattern , where , one operation chooses any two positions in and swaps their characters. Find the minimum number of operations needed so that no longer contains as a substring.
Constraints: , adjacent characters in are distinct (), and may contain arbitrary additional characters.
Because swapping preserves the multiset of characters, the problem is equivalent to finding, among all rearrangements of that avoid , one with minimum swap distance from (the Cayley distance in the permutation case).
Two properties
The solution repeatedly uses two facts that follow directly from the statement:
- One swap changes at most two positions. Every lower bound below comes from this fact.
- Adjacent characters in are distinct. Therefore, any segment containing two equal adjacent characters cannot match . This lets us destroy target occurrences without creating new ones.
1. Example
It satisfies the constraint, and its first and last characters are equal: . This will matter later.
The character z does not appear in and only separates groups of occurrences.
Use KMP to find every starting position of in . There are seven:
Visualized on :

Number these occurrences from left to right as #0, #1, ..., #6. Occurrence starts at and occupies .
Because adjacent characters in differ, the starting positions of two occurrences differ by at least two. The prefix group starts at , exactly two apart.
2. Shared positions and blocks
Destroying an occurrence requires changing at least one position inside it.
The first four occurrences overlap. If one position belongs to several occurrences, changing that single position destroys all of them. This suggests the following reformulation:
Partition the occurrences from left to right into blocks such that all occurrences in each block share at least one common position. Changing one shared position destroys the entire block.
For occurrences #i through #j, their common intersection is . It is nonempty exactly when
Its width is . This width gives two kinds of blocks.
3. Flexible and rigid blocks
Flexible block: common width at least 2
The condition is .
Consider #0,#1,#2, starting at with :

Their common intersection has three positions. The formula gives . Any of these shared positions can be changed, so the block is flexible.
Rigid block: common width exactly 1
The condition is .
Consider #0 and #3, whose starts differ by :

The only shared position is , so it must be changed. This position is simultaneously:
- the final character of
#0, equal to ; - the first character of
#3, equal to .
Therefore a rigid block can exist only if . Its shared character is fixed as
For abababa, both are a, so rigid blocks are possible. If the endpoints of differ, the algorithm immediately takes the simpler branch with no rigid blocks.
A flexible block offers several shared positions to change. A rigid block offers exactly one, whose original character must be . All later complexity comes from this distinction.
4. The partition DAG
There are several ways to partition the occurrences. They produce different numbers of flexible and rigid blocks, and therefore different costs. We represent every valid partition in a directed acyclic graph.
4.1 State order
Process occurrences from left to right. A state means that occurrence #i is the leftmost occurrence not yet covered by a block. The next block must begin with #i.
- The initial state is .
- After choosing a block, move to the first occurrence outside it.
- After all occurrences are covered, reach terminal state .
4.2 Two maximal choices
At state , only two maximal choices matter.
(A) Maximum flexible block. Starting from #i, include as many following occurrences as possible while the first and last starts differ by at most . This choice always exists.
(B) Rigid block. If the immediately following occurrence outside the maximum flexible block starts exactly at , include it as well. The common width shrinks to one, producing a rigid block.
Each choice becomes an edge in the DAG.
4.3 Enumerating the example
Here , so a flexible block permits a span at most five and a rigid block requires a span of six. The occurrence starts are .
| State | Maximum flexible block | Flexible destination | Rigid choice |
|---|---|---|---|
| state | |||
| state | none | ||
| state | none | ||
| state | none | ||
| state | none |
States and never appear as starting states because the flexible edge from state already covers them.
4.4 Paths
The states and choices form the following DAG, with rigid edges shown in red:

There are two paths in the example:
- All flexible: , giving five flexible blocks.
- With one rigid edge: , giving four blocks, one of them rigid.
Define
The flexible edge is . If , there is also a rigid edge .
The next task is to compute the cost of a path.
5. Cost of a path:
Suppose a path contains flexible blocks and rigid blocks. Its minimum number of swaps is
The two terms are lower bounds, and both can be achieved simultaneously.
5.1 Pairing lower bound
One swap changes at most two positions. Every block needs at least one changed position, and distinct blocks use distinct positions. Therefore, for swaps,
Equivalently, one swap can destroy at most two blocks.
5.2 Rigid-block lower bound
The unique shared position of every rigid block initially contains and must be changed to another character.
Let be the set of positions whose original character is . Initially, no position in contains a non- character. One swap can increase that number by at most one. After swaps, at most originally- positions can contain non- characters. Since every rigid block needs one, .
5.3 Upper bound: pairing with safe swaps
We construct swaps that destroy only their target blocks and create no new occurrence of . This uses the second property: two equal adjacent characters make a match impossible.
In the common part of a flexible block, choose a position and change it to match a neighbor. For example, turn into . The resulting equal adjacent pair destroys every occurrence in the block. Pair this target position with a target position in another block, and one swap destroys both blocks. A rigid block works similarly, except its unique position is forced.
Consider isolated flexible blocks #4 and #5, both equal to abababa. Choose the penultimate character of #4 (position 35, b) and the final character of #5 (position 46, a) and swap them:

Both occurrences disappear in one swap, and no new abababa appears. The new aaa and bb segments cannot occur inside , whose adjacent characters always differ.
Combining such swaps gives the bound: pair rigid blocks with flexible ones when possible, pair remaining flexible blocks together, and handle leftover rigid blocks individually. The result is exactly
Some useful construction details:
- A flexible block has several safe candidate positions near its ends. One block can use a change while another uses the complementary , allowing a direct swap.
- To keep multiple swaps from interfering, order flexible blocks by position, assign one change direction to the left half and the complementary direction to the right half, then pair across the halves.
- A rigid block simply changes its unique position. It may pair with a flexible block, while a leftover rigid or flexible block can be handled in one swap.
For path 2 in the example, and :

5.4 The two example paths
| Path | Blocks | Cost | ||
|---|---|---|---|---|
| all flexible | flex{#0,#1,#2}, flex{#3}, flex{#4}, flex{#5}, flex{#6} | 5 | 0 | |
| one rigid | rigid{#0..#3}, flex{#4}, flex{#5}, flex{#6} | 3 | 1 |
The optimum is two swaps. The rigid edge merges two flexible blocks into one, reducing the total block count from five to four without making the bottleneck.
6. Minimizing
We now need to minimize
over all paths from to .
6.1 Reduction to
For a fixed total number of blocks , only the minimum achievable number of rigid blocks matters. Define
Then
6.2 An DP
Run dynamic programming on the DAG. Every edge contributes exactly one block; a rigid edge additionally contributes one rigid block.
Let dp[i] map a number of blocks to the minimum rigid count for a path from state to .
- Base case:
dp[r] = {0 blocks: 0 rigid}. - Flexible edge to : transform each in
dp[g_i]into . - Rigid edge to : transform each into .
- For the same , keep the smaller .
There are states and each table has size , for total time.
In the example,
so
This is sufficient for moderate input sizes. The remaining sections optimize for as many as occurrences.
6.3 Convexity of
has two useful properties:
- It is non-increasing: using more blocks makes it easier to avoid forced rigid merges.
- It is convex: .
The answer becomes visible when the two bounds are plotted together:

- increases with .
- decreases and is convex.
- Their pointwise maximum is U-shaped, and its minimum is the answer.
The figure is illustrative; it uses a sample convex sequence to show the shape.
6.4 Parametric optimization and slope binary search
Instead of enumerating , assign cost to every flexible block and to every rigid block:
For fixed , this is a linear shortest-path DP on the DAG: flexible edges cost and rigid edges cost . A reverse scan evaluates it in .
Convexity of gives
is concave and piecewise linear. Binary-search its slope to find the maximum. To avoid floating-point errors, search a grid with denominator and compute the final intersection exactly with __int128.
7. Complete algorithm
- Use KMP to find all occurrence starts . If there are none, return zero.
- Use two pointers to compute every , the destination of the maximum flexible block.
- If , no rigid block exists. Greedily follow flexible edges, count the blocks , and return .
- Otherwise maximize , or use the DP for smaller inputs, and return .
8. Complexity
KMP and DAG construction take . Each fixed- DP takes , and the binary search uses about 54 evaluations. The total is
The proof never requires and to use the same alphabet, so arbitrary extra characters in do not affect correctness.
9. Reference implementation
The core is a linear DP on the DAG plus slope binary search. For smaller inputs, the rigid branch can be replaced with the table DP from Section 6.2.
#include <bits/stdc++.h>
using namespace std;
using i128 = __int128_t;
struct Line { int c; int d; }; // c = 2*rigid, d = flexible - rigid
struct Node { Line mn; Line mx; };
static inline i128 get_value(const Line& line, long long num, long long den) {
return (i128)line.c * den + (i128)line.d * num;
}
static inline long long ceil_div(i128 a, i128 b) {
return (long long)((a + b - 1) / b);
}
// Return every starting position where t occurs in s.
vector<int> find_occurrences(const string& s, const string& t) {
const int n = (int)s.size(), m = (int)t.size();
vector<int> pi(m), occ;
for (int i = 1, j = 0; i < m; ++i) {
while (j > 0 && t[i] != t[j]) j = pi[j - 1];
if (t[i] == t[j]) ++j;
pi[i] = j;
}
for (int i = 0, j = 0; i < n; ++i) {
while (j > 0 && s[i] != t[j]) j = pi[j - 1];
if (s[i] == t[j]) ++j;
if (j == m) { occ.push_back(i - m + 1); j = pi[j - 1]; }
}
return occ;
}
long long solve_query(const string& s, const string& t) {
const int m = (int)t.size();
assert(m >= 3);
vector<int> occ = find_occurrences(s, t);
const int r = (int)occ.size();
if (r == 0) return 0;
// go[i] is the state reached after taking the maximum flexible block.
vector<int> go(r);
for (int i = 0, j = 0; i < r; ++i) {
j = max(j, i + 1);
const int limit = occ[i] + m - 2;
while (j < r && occ[j] <= limit) ++j;
go[i] = j;
}
// Different endpoints imply that rigid blocks cannot exist.
if (t.front() != t.back()) {
int blocks = 0;
for (int i = 0; i < r; i = go[i]) ++blocks;
return (blocks + 1LL) / 2;
}
// At each state, keep optimal lines with minimum and maximum slope.
vector<int> c_min(r + 1), d_min(r + 1), c_max(r + 1), d_max(r + 1);
auto evaluate = [&](long long num, long long den) -> Node {
c_min[r] = d_min[r] = c_max[r] = d_max[r] = 0;
for (int i = r - 1; i >= 0; --i) {
const int j = go[i];
Line flex_min{ c_min[j], d_min[j] + 1 };
Line flex_max{ c_max[j], d_max[j] + 1 };
Line result_min = flex_min, result_max = flex_max;
i128 best = get_value(flex_min, num, den);
// A rigid edge exists exactly when the next start is occ[i]+m-1.
if (j < r && occ[j] == occ[i] + m - 1) {
Line rigid_min{ c_min[j + 1] + 2, d_min[j + 1] - 1 };
Line rigid_max{ c_max[j + 1] + 2, d_max[j + 1] - 1 };
i128 cand = get_value(rigid_min, num, den);
if (cand < best) {
best = cand;
result_min = rigid_min;
result_max = rigid_max;
} else if (cand == best) {
if (rigid_min.d < result_min.d) result_min = rigid_min;
if (rigid_max.d > result_max.d) result_max = rigid_max;
}
}
c_min[i] = result_min.c; d_min[i] = result_min.d;
c_max[i] = result_max.c; d_max[i] = result_max.d;
}
return Node{ {c_min[0], d_min[0]}, {c_max[0], d_max[0]} };
};
constexpr long long DEN = 1LL << 50;
Node at_zero = evaluate(0, DEN);
if (at_zero.mn.d <= 0)
return ceil_div(get_value(at_zero.mn, 0, DEN), (i128)2 * DEN);
Node at_one = evaluate(DEN, DEN);
if (at_one.mx.d >= 0)
return ceil_div(get_value(at_one.mn, DEN, DEN), (i128)2 * DEN);
long long left = 0, right = DEN;
while (right - left > 1) {
const long long mid = (left + right) >> 1;
Node cur = evaluate(mid, DEN);
if (cur.mn.d <= 0 && cur.mx.d >= 0)
return ceil_div(get_value(cur.mn, mid, DEN), (i128)2 * DEN);
if (cur.mn.d > 0) left = mid;
else right = mid;
}
Node left_node = evaluate(left, DEN);
Node right_node = evaluate(right, DEN);
Line lhs = left_node.mn;
Line rhs = right_node.mx;
const long long den = lhs.d - rhs.d;
const i128 h_num = (i128)lhs.d * rhs.c - (i128)rhs.d * lhs.c;
return ceil_div(h_num, (i128)2 * den);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int Q; cin >> Q;
while (Q--) {
string S, T; cin >> S >> T;
cout << solve_query(S, T) << '\n';
}
return 0;
}
Why the restrictions matter
- Adjacent characters in are distinct. This keeps occurrence starts at least two positions apart and gives the clean flexible/rigid block structure. Without it, overlaps become more complicated and the DAG argument fails.
- . Patterns of length two form a different problem. For example, and have only one occurrence, but the answer is two, so the block cost formula no longer applies.
- The partition depends only on which positions violate the constraint, not on the distance metric. Replacing arbitrary swaps (Cayley distance) with Hamming distance or adjacent swaps (Kendall tau distance) should lead to related variants.