CF 102697085 - Pattern Two
The task asks us to decide whether a string contains a repeated substring that appears exactly the requested number of times consecutively. Unlike the previous pattern problem, the repeated section is allowed to begin at any position in the input string.
Rating: -
Tags: -
Solve time: 1m 25s
Verified: yes
Solution
Problem Understanding
The task asks us to decide whether a string contains a repeated substring that appears exactly the requested number of times consecutively. Unlike the previous pattern problem, the repeated section is allowed to begin at any position in the input string. Characters before the repetition and after the repetition do not matter. The repeated block itself must contain at least two characters, following the rule established by the preceding problem in the contest. The official statement gives a string on the first input line and the required repetition count on the second line, and the answer is True or False.
For example, with abcXYZXYZXYZdef and a requested count of 3, the substring XYZ is repeated three times, so the answer is True. With abcXYXYdef and a requested count of 3, only two copies of XY occur, so that particular pattern does not satisfy the request.
The statement does not provide an explicit maximum length for the input string. That changes how we should reason about complexity. A direct cubic search can become expensive surprisingly quickly, while an O(n²) solution gives a much safer bound for a one-second limit. Since there is no published numeric bound for n, we should avoid relying on a tiny fixed string length even though this is an introductory contest problem. The official limits are one second and 256 MB.
There are several edge cases that a naive implementation can mishandle. First, the repeated block must have at least two characters. For input
aaaaa
2
the correct output is True, because aa occurs twice consecutively. A careless solution that only searches for a repeated character could accept the input for the wrong reason, while a solution that accidentally allows a block of length one may report patterns that the preceding problem explicitly forbids.
A second edge case is that the repetition does not have to start at position zero. For input
xxabcabcabczz
3
the correct output is True. A solution inherited directly from the previous problem and only checking prefixes would incorrectly return False, because the useful repetition starts at index 2.
A third edge case is irrelevant text after the repetition. For input
abcabcXYZ
2
the correct output is True. The abcabc section is a valid two-copy repetition and the trailing XYZ is ignored. This is explicitly part of the intended pattern behavior.
Finally, a repetition can have a longer repeated run than the requested count. For input
HELLOHELLOHELLOHELLOHELLO
4
the answer is still True, because four consecutive copies of HELLO form a valid repeated section, with the remaining copy treated as surrounding text. The phrase “precisely matches” refers to the selected repetition section having the requested number of copies, not to requiring the entire maximal run in the input to contain exactly that many copies.
Approaches
The most direct brute-force approach is to try every possible starting position and every possible length of the repeated block. For a start position i and block length L, we construct the candidate block s[i:i+L] and compare the following k - 1 blocks with it. If all of them match, we have found the required pattern.
This approach is correct because every possible repeated section has some starting position and some block length, so enumerating both parameters cannot miss a valid answer. The problem is the amount of repeated work. There can be O(n²) choices of (i, L), and checking one candidate can inspect O(kL) characters. With k treated as part of the input, the worst case is cubic in the string length, and even for a fixed small k the total work remains Θ(n³). A string of length 1000 can already lead to hundreds of millions of character-level comparisons in the worst case.
The useful observation is that, once the starting position and block length are fixed, we do not really need to compare all copies independently. Suppose the candidate starts at i and has length L. The condition that k copies are equal is exactly
S[i : i + (k-1)L] = S[i+L : i+kL].
In other words, the suffix beginning at i must agree with the suffix beginning at i+L for at least (k-1)L characters.
This is exactly the kind of query answered by a Z-function. For a suffix beginning at i, the Z value at offset L tells us the length of the longest common prefix between that suffix and the suffix beginning L characters later. If that value is at least (k-1)L, then the first k blocks of length L are identical.
We compute a Z-array separately for each possible starting position. Computing the Z-array for a suffix of length m costs O(m), and the lengths of all suffixes add up to O(n²). After obtaining the Z-array for one starting position, checking all possible block lengths costs another O(n), giving an overall O(n²) algorithm.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | O(n³) | O(n) | Too slow in the worst case |
| Optimal | O(n²) | O(n) | Accepted |
Algorithm Walkthrough
- Read the string
sand the requested repetition countk. Ifk < 2, returnFalse, because a repetition requires at least two copies of a block. - Let
nbe the length of the string. A repeated block must contain at least two characters and must fitktimes inside the remaining suffix. For a starting positionstart, the largest possible block length is therefore(n - start) // k. - For each possible
start, build the Z-array of the suffixs[start:]. In this Z-array,z[L]is the length of the longest prefix ofs[start:]that is also equal to the substring beginningLcharacters later. - Try every block length
Lfrom2through(n - start) // k. We needkcopies of this block, so the first copy must match the nextk - 1copies for a total of(k - 1) * Lcharacters. - If
z[L] >= (k - 1) * L, the substring beginning atstartconsists of at leastkconsecutive copies of the same block. ReturnTrueimmediately. - If every starting position and every possible block length fails, return
False.
The key invariant is that for a fixed start, z[L] exactly measures how many characters after the first block continue to agree with the string shifted by L positions. Consequently, z[L] >= (k-1)L is equivalent to equality of all k copies. Since every valid repetition has some start and some block length, the nested search considers every possible answer, and the algorithm can only return True when the required equality actually holds.
Python Solution
import sys
input = sys.stdin.readline
def has_pattern(s: str, k: int) -> bool:
n = len(s)
if k < 2:
return False
for start in range(n):
m = n - start
if m < 2 * k:
continue
t = s[start:]
z = [0] * m
left = right = 0
for i in range(1, m):
if i < right:
z[i] = min(right - i, z[i - left])
while i + z[i] < m and t[z[i]] == t[i + z[i]]:
z[i] += 1
if i + z[i] > right:
left = i
right = i + z[i]
max_len = m // k
for length in range(2, max_len + 1):
if z[length] >= (k - 1) * length:
return True
return False
def solve():
s = input().rstrip("\n")
k = int(input())
print("True" if has_pattern(s, k) else "False")
if __name__ == "__main__":
solve()
The has_pattern function contains the complete algorithm. The early k < 2 check handles an invalid repetition count before any string processing begins.
For every start, t represents the suffix beginning at that position. We build its Z-array using the standard [left, right) matching window. When i lies inside the current window, the value from the corresponding mirrored position can be reused as a lower bound, avoiding unnecessary character comparisons.
The loop over length begins at 2, rather than 1, because the repeated block must have at least two characters. The upper bound is m // k, because a block longer than that cannot fit k times in the suffix.
The condition z[length] >= (k - 1) * length is the central implementation detail. We do not need to construct block * k, and we do not need to compare each copy separately. The Z value already represents the entire comparison between the first copy and everything after it shifted by one block.
There is no integer overflow issue in Python. The largest expression involving the repetition count is (k - 1) * length, which Python handles with arbitrary-precision integers.
The input string is read with rstrip("\n") rather than strip(), because spaces are legitimate characters in the string and must remain part of the input.
Worked Examples
For the first example, the input is the official sample:
uyboubawlefjbasdHELLOHELLOHELLOHELLOsygvfubklkj
4
At the beginning of the string there is no useful repetition. Eventually start reaches the first H of HELLO.
| start | candidate length | required Z value | actual Z value | result |
|---|---|---|---|---|
| 16 | 2 | 6 | less than 6 | reject |
| 16 | 3 | 9 | less than 9 | reject |
| 16 | 4 | 12 | less than 12 | reject |
| 16 | 5 | 15 | 15 | accept |
The block length is 5, so (k-1)L = 3 * 5 = 15. The suffix beginning at the first H matches the suffix beginning five characters later for 15 characters, exactly covering the next three copies. The algorithm returns True. This matches the official sample output.
A second example demonstrates why the starting position cannot be assumed to be zero:
xxabcabcabczz
3
| start | candidate length | required Z value | actual Z value | result |
|---|---|---|---|---|
| 0 | 2 | 4 | less than 4 | reject |
| 1 | 2 | 4 | less than 4 | reject |
| 2 | 2 | 4 | less than 4 | reject |
| 2 | 3 | 6 | 6 | accept |
At start = 2, the block is abc. Three copies require six matching characters after the first copy, and the Z value at offset 3 is 6. The algorithm accepts the string without requiring the repeated section to begin at the first character.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n²) | A Z-array of every suffix costs O(n²) in total, and the block-length checks also total O(n²) |
| Space | O(n) | Only the current suffix and its Z-array are stored |
The official time limit is one second and the memory limit is 256 MB. Since the statement does not publish a maximum string length, an O(n²) solution is a safer choice than the cubic brute force. The algorithm also avoids storing an O(n²) table, so its memory usage remains linear.
Test Cases
import sys
import io
def has_pattern(s: str, k: int) -> bool:
n = len(s)
if k < 2:
return False
for start in range(n):
m = n - start
if m < 2 * k:
continue
t = s[start:]
z = [0] * m
left = right = 0
for i in range(1, m):
if i < right:
z[i] = min(right - i, z[i - left])
while i + z[i] < m and t[z[i]] == t[i + z[i]]:
z[i] += 1
if i + z[i] > right:
left = i
right = i + z[i]
for length in range(2, m // k + 1):
if z[length] >= (k - 1) * length:
return True
return False
def run(inp: str) -> str:
old_stdin = sys.stdin
sys.stdin = io.StringIO(inp)
s = sys.stdin.readline().rstrip("\n")
k = int(sys.stdin.readline())
ans = "True" if has_pattern(s, k) else "False"
sys.stdin = old_stdin
return ans + "\n"
# Provided sample
assert run(
"uyboubawlefjbasdHELLOHELLOHELLOHELLOsygvfubklkj\n4\n"
) == "True\n", "sample 1"
# Minimum useful repetition
assert run("abab\n2\n") == "True\n", "minimum repeated block"
# Repetition starts after irrelevant text
assert run("xxabcabcabczz\n3\n") == "True\n", "nonzero starting position"
# Requested number is too large
assert run("abcabc\n3\n") == "False\n", "not enough repetitions"
# A single-character block must not count
assert run("aaaa\n3\n") == "False\n", "block length must be at least two"
# More copies than requested are still enough to select the requested section
assert run("HELLOHELLOHELLOHELLOHELLO\n4\n") == "True\n", "longer run"
# Boundary case where the pattern reaches the end exactly
assert run("zzxyxyxy\n3\n") == "True\n", "pattern reaches string end"
# No repeated section
assert run("abcdefgh\n2\n") == "False\n", "no repetition"
| Test input | Expected output | What it validates |
|---|---|---|
abab, 2 |
True |
Smallest valid repeated block |
xxabcabcabczz, 3 |
True |
Repetition can start away from the beginning |
abcabc, 3 |
False |
Insufficient number of copies |
aaaa, 3 |
False |
A one-character block is not a valid pattern |
HELLO repeated five times, 4 |
True |
Surrounding text can exist beyond the selected repetition |
zzxyxyxy, 3 |
True |
Repetition ending exactly at the final character |
abcdefgh, 2 |
False |
Completely non-repeating input |
Edge Cases
For the minimum valid block length, consider
abab
2
The algorithm reaches start = 0 and tries length = 2. The suffix is abab, while the suffix shifted by two positions is ab. The Z value at offset 2 is 2, which equals (2-1) * 2. The algorithm returns True. A solution that accidentally starts its length loop at 3 would miss this valid pattern.
For a pattern that does not begin at the first character, consider
xxabcabcabczz
3
The first two positions are rejected because no suitable three-copy pattern begins there. At position 2, the candidate block abc has length 3. The Z value at offset 3 is 6, while the required value is (3-1) * 3 = 6. The algorithm returns True, correctly ignoring the xx prefix and zz suffix.
For an input where there are not enough copies, consider
abcabc
3
The only plausible repeated block has length 2 or 3, but three copies would require at least six characters for a two-character block and nine characters for a three-character block. The only six-character candidate is abcabc, which contains two copies, not three. Every candidate fails the Z threshold, so the answer is False.
For the minimum block-size restriction, consider
aaaa
3
The string contains three copies of a, but the repeated block has length one. Since the pattern inherited from the previous problem requires the repeated string to contain at least two characters, the algorithm never tests length = 1. It returns False.
For extra copies, consider
HELLOHELLOHELLOHELLOHELLO
4
At the first H, length = 5 gives a Z value large enough to cover three subsequent copies. The algorithm accepts immediately. The fifth HELLO does not invalidate the selected four-copy repetition because the problem allows irrelevant text around the repeated section.