n, s = int(input()), input() N = len(s) def _solve(): # 检查是否以 '1' 结尾 if s[-1] != '1': return "-1" # 收集所有 '1' 的位置(0-based) oi = [-1] # 初始化为 -1,方便处理第一个区间 for i in range(N): if s[i] == '1': oi.append(i) no = len(oi) # '1' 的个数 + 1(因为初始有 -1) d = [0] * n # 从后往前处理每个 '1' 的区间 for i in range(no - 1, 0, -1): num = oi[i] + 1 # 当前 '1' 的 1-based 位置 index = oi[i - 1] + 1 # 前一个 '1' 的 1-based 位置 d[index] = num # 将前一个 '1' 的下一个位置设置为 num # 填充递减序列 k = num - 1 for j in range(index + 1, num): d[j] = k k -= 1 return " ".join(map(str, d)) def solve(): res = _solve() print(res) solve()
题目重述
我们有一个由 0
和 1
组成的字符串 s
和一个长度为 n
的排列 p
。定义 s
和 p
匹配的条件如下:
- 如果
s[i] == '1'
,那么p[1..i]
必须是一个排列(即包含1
到i
的所有整数,每个整数恰好出现一次)。 - 如果
s[i] == '0'
,那么p[1..i]
不能是一个排列。
给定字符串 s
,构造一个满足条件的排列 p
,如果不存在这样的排列,则输出 -1
。
解题思路
我们需要构造一个排列 p
,使得对于每个位置 i
:
- 如果
s[i] == '1'
,那么p[1..i]
是1
到i
的排列。 - 如果
s[i] == '0'
,那么p[1..i]
不是1
到i
的排列。
关键观察:
- **
s
必须以'1'
结尾**:因为p[1..n]
必须是一个排列(1
到n
的排列),所以s[n-1]
必须是'1'
(因为 Python 是 0-based 索引,题目中s
是 1-based 索引时s[n]
必须是'1'
)。如果s
以'0'
结尾,直接返回-1
。 - **
'1'
的位置**:假设s
中有k
个'1'
,分别出现在位置i_1, i_2, ..., i_k
(其中i_k = n-1
)。那么:对于每个 i_j,p[1..i_j] 必须是 1 到 i_j 的排列。对于 i_{j-1} + 1 到 i_j - 1 的位置(即两个 '1' 之间的 '0' 区域),p[1..m] 不能是 1 到 m 的排列(其中 m 在这些位置之间)。
构造方法:
- 处理 '1' 的位置:对于每个 '1' 的位置 i_j,p[1..i_j] 必须是 1 到 i_j 的排列。因此,我们可以将 p[1..i_j] 设置为 1 到 i_j 的某种排列。为了满足 '0' 的条件,我们需要确保在两个 '1' 之间的 '0' 区域中,p 的构造不会让 p[1..m] 成为 1 到 m 的排列。
- 具体构造:假设 '1' 的位置是 i_1, i_2, ..., i_k(按顺序)。对于 i_j,p[1..i_j] 是 1 到 i_j 的排列。我们可以将 p[i_{j-1}+1..i_j] 设置为 i_j - i_{j-1} 到 1 的递减序列(即 i_j - i_{j-1}, ..., 1),然后将前面的部分调整为满足排列的条件。这样,对于 '0' 的位置 m(i_{j-1} < m < i_j),p[1..m] 会缺少 i_j - i_{j-1} - (m - i_{j-1}) 的一些数,因此不是 1 到 m 的排列。
代码步骤:
- 输入处理:读取 n 和字符串 s。N 是 s 的长度(实际上是 n)。
- 检查 s 是否以 '1' 结尾:如果不是,直接返回 -1。
- 收集所有 '1' 的位置:oi 是一个列表,初始化为 [-1],然后收集所有 '1' 的 0-based 索引。
- **初始化结果数组 d**:d 是长度为 n 的数组,初始化为 0。
- 从后往前处理 '1' 的区间:no 是 '1' 的个数 + 1(因为 oi 初始有 -1)。从最后一个 '1' 开始往前处理:num 是当前 '1' 的 1-based 位置(oi[i] + 1)。index 是前一个 '1' 的 1-based 位置(oi[i-1] + 1)。将 d[index] 设置为 num(即前一个 '1' 的下一个位置是 num)。然后从 index + 1 到 num - 1 填充递减序列 num - 1, num - 2, ..., 1。
- 返回结果:将 d 转换为字符串输出。
总结
该算法的核心是通过从后往前处理 '1'
的位置,确保每个 '1'
对应的前缀是一个排列,而 '0'
对应的前缀不是排列。通过填充递减序列,可以高效地构造出满足条件的排列。如果 s
不以 '1'
结尾,则直接判定无解。