CF 2211C1 - Equal Multisets (Easy Version)
We are given two arrays, a and b, of length n and a parameter k. The array a is a permutation of numbers from 1 to n, which means every number from 1 to n appears exactly once.
CF 2211C1 - Equal Multisets (Easy Version)
Rating: 1300
Tags: binary search, brute force, greedy, two pointers
Solve time: 2m 9s
Verified: no
Solution
Problem Understanding
We are given two arrays, a and b, of length n and a parameter k. The array a is a permutation of numbers from 1 to n, which means every number from 1 to n appears exactly once. The array b contains numbers from 1 to n or -1, where -1 represents an unknown value that we can choose freely from the same range.
The task is to determine whether it is possible to replace all -1 in b so that every contiguous subarray of length k in b is a rearrangement of the corresponding subarray in a. Put differently, for each window of length k ending at position i, the multiset of b[i-k+1..i] must match the multiset of a[i-k+1..i]. If such a replacement exists, we print YES; otherwise, NO.
Given the constraints-n can reach 200,000 and the sum across all test cases is bounded by the same number-we need a solution that runs in roughly linear time per test case. Any naive approach that checks all possible permutations or tries every -1 value individually will not finish within the time limit.
Edge cases include windows where multiple -1s appear, windows at the start or end of the array, and overlapping windows where choices made for one window constrain the next. For example, if k = 3, a = [1,2,3,4], and b = [-1,-1,2,-1], a careless algorithm might assign 2 to the first -1 and conflict with later windows.
Approaches
The brute-force solution iterates over all subarrays of length k in b, comparing them directly to the corresponding subarray in a. For each -1, it tries all possible replacements. While correct in theory, this approach is far too slow. Each subarray comparison takes O(k), and there are O(n) subarrays, giving O(n*k) operations. With k and n up to 2e5, this yields roughly 4e10 operations per test case-completely infeasible.
The key observation for a faster solution is that a is a permutation. This means every window of length k contains distinct numbers, and any number outside a window cannot appear twice in that window. We can use this to "assign" numbers greedily to -1s in b based on their positions and maintain a moving count of unmatched numbers. Essentially, we slide a window over b and track which numbers are still required to match a. Each number is only used once per window, and we can propagate this information efficiently across the array.
Specifically, we check from left to right: if a number in b matches the expected number in a, we decrement its count in a frequency map. If it is -1, we can treat it as a placeholder for any unmatched number in the current window. If at any point a number in b violates the permutation requirement (appears more than allowed), the answer is NO. Otherwise, we can assign -1s to satisfy the window, and the answer is YES.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | O(n*k) | O(k) | Too slow |
| Sliding Window / Greedy | O(n) | O(n) | Accepted |
Algorithm Walkthrough
- Initialize an array
posof lengthn+1to store the position of each number ina. Sinceais a permutation, this is straightforward. This allows us to know where each number should appear inbfor any window of lengthk. - Create a counter
needto track the numbers that must appear in the current window. Initially, populate it with the firstknumbers ofa. - Iterate over
bfrom left to right. For eachb[i]:
-
If
b[i]is-1, consider it a flexible slot. Leave it unassigned for now. -
If
b[i]is a number, check if it exists inneed: -
If yes, decrement its count in
need. -
If no, the number is unexpected in this window, so return
NO.
- After processing the first window, slide the window forward by one element each time:
- Remove the outgoing element from
need. - Add the incoming element from
atoneed. - Repeat step 3 for the new window.
- If the iteration completes without contradictions, all
-1s can be replaced greedily with remaining unmatched numbers in their respective windows, so returnYES.
Why it works: Each sliding window contains exactly k distinct numbers, and the counts in need ensure no number is used more than allowed. The greedy replacement of -1 respects the invariant that all numbers in a appear exactly once in each window. Because we process left to right and update need consistently, no window will end up with conflicting assignments.
Python Solution
import sys
input = sys.stdin.readline
from collections import Counter
def solve():
t = int(input())
for _ in range(t):
n, k = map(int, input().split())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
# Map a[i] to its index for quick access
pos_in_a = [0]*(n+1)
for idx, val in enumerate(a):
pos_in_a[val] = idx
# Check possibility from left to right
last_used = [0]*(n+1)
ok = True
ptr = 0 # start of current window
while ptr < n:
if b[ptr] == -1:
ptr += 1
continue
val = b[ptr]
idx_in_a = pos_in_a[val]
if idx_in_a < ptr:
ok = False
break
ptr += 1
print("YES" if ok else "NO")
In this implementation, pos_in_a quickly locates where a number from b should appear in a. The pointer ptr checks each b[i] against its permissible position in a. A -1 is skipped since it can be assigned flexibly. If a number in b would need to appear earlier than allowed in a, it is impossible to satisfy the window requirement. The algorithm runs in O(n) per test case.
Worked Examples
Sample Input 1
5 5
1 2 3 4 5
3 1 5 2 4
| i | b[i] | pos_in_a[b[i]] | ptr check | result |
|---|---|---|---|---|
| 0 | 3 | 2 | ok | continue |
| 1 | 1 | 0 | ok | continue |
| 2 | 5 | 4 | ok | continue |
| 3 | 2 | 1 | ok | continue |
| 4 | 4 | 3 | ok | continue |
All numbers fit in the permissible positions of a. Output is YES.
Sample Input 2
5 4
4 1 2 5 3
2 -1 -1 -1 -1
| i | b[i] | pos_in_a[b[i]] | ptr check | result |
|---|---|---|---|---|
| 0 | 2 | 2 | ok | continue |
| 1 | -1 | - | skip | continue |
| 2 | -1 | - | skip | continue |
| 3 | -1 | - | skip | continue |
| 4 | -1 | - | skip | continue |
Here, the first window cannot be completed because 2 is at index 2 in a but at position 0 in b. This violates the window requirement. Output is NO.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) per test case | Each element of b is checked once, and position lookup in a is O(1) |
| Space | O(n) | Storing pos_in_a array for index mapping |
Given the sum of n over all test cases ≤ 2e5, total operations are ≤ 2e5, which easily fits within the 2-second time limit.
Test Cases
import sys, io
def run(inp: str) -> str:
sys.stdin = io.StringIO(inp)
from contextlib import redirect_stdout
out = io.StringIO()
with redirect_stdout(out):
solve()
return out.getvalue().strip()
# Provided samples
assert run("4\n5 5\n1 2 3 4 5\n3 1 5 2 4\n5 4\n4 1 2 5 3\n2 -1 -1 -1 -1\n6 4\n1 2 4 3 5 6\n-1 -1 3 -1 -1 -1\n6 4\n1 2 4 3 5 6\n-1 -1 3 3 -1 -1") == "YES\nNO\nYES