#CF2146C. 错误二分查找
错误二分查找
C. 错误二分查找
每次测试时间限制: 秒
每次测试内存限制: 兆字节
题目描述
给定一个整数 和一个长度为 的二进制字符串 。
对于一个长度为 的排列 和一个整数 ,我们定义 的伪代码如下:
function find(int x):
l := 1
r := n
while l <= r:
let m be a random integer between l and r (inclusive)
if p[m] == x:
return m
if p[m] > x:
r := m - 1
else:
l := m + 1
return undefined // 未找到
我们称整数 ()是稳定的,当且仅当无论 过程中如何随机选择 ,它总是返回一个确定的值(不是未定义),并且 始终成立。
你必须构造一个长度为 的排列 ,使得:
- 对于每个 ,整数 是稳定的当且仅当 。
或者判断这样的排列不存在。
注意:
- 二进制字符串是指每个字符为 或 的字符串。
- 长度为 的排列是由 个不同的整数 到 以任意顺序组成的数组。例如, 是一个排列,但 不是( 出现了两次), 也不是( 但数组中有 )。
输入
每个测试包含多个测试用例。第一行包含一个整数 (),表示测试用例的数量。接下来是每个测试用例的描述。
每个测试用例的第一行包含一个整数 (),表示排列的长度。
第二行包含一个长度为 的二进制字符串 ()。
保证所有测试用例的 之和不超过 。
输出
对于每个测试用例:
- 如果不存在这样的排列,则输出一行
"NO"。 - 否则,第一行输出
"YES",第二行输出 个不同的整数 (),表示你构造的排列。
你可以以任意大小写输出答案(例如,"yEs"、"yes"、"Yes" 和 "YES" 均视为肯定答案)。
如果有多个答案,你可以输出任意一个。
示例
输入:
6
3
111
5
00000
5
10100
7
0010000
11
00001001100
12
011100010000
输出:
YES
1 2 3
YES
2 4 3 5 1
NO
YES
2 1 3 5 7 6 4
YES
2 1 4 3 5 7 6 8 9 11 10
NO
注释
第一个测试用例:我们构造了 。以 为例:
- 初始 ,;
- 随机选择 在 之间:
- 若 :,所以 ,此时 ;
- 再随机选 :
- :,返回 ;
- :,则 ,此时 ,只能选 ,,返回 。
- 再随机选 :
- 若 :,直接返回 。
- 若 :,则 ,此时 ;
- 再选 :
- :,,此时 ,只能选 ,返回 ;
- :,返回 。
- 再选 :
- 若 :,所以 ,此时 ;
- 总之,无论随机选择如何, 总是返回 ,因此 稳定。
同理可证 和 也稳定。因此 是一个合法答案。
第二个测试用例:构造 。以 为例:
- 初始 ;
- 若选 :,则 ,此时 ;
- 只能选 :,则 ,此时 ,退出循环,返回未定义。
- 因此 可能返回未定义,故 不稳定。
同理可证 也不稳定。所以 是合法答案。其他如 或 也是合法答案。
第三个测试用例:可以证明不存在这样的排列。