本题知识点:模拟
这是一道恐怖的括号题。题意稍微理解以下还是可以的。
我们针对样例来理解一下 S、P、W 到底是什么意思:
S:( ( ( ( ) ( ) ( ) ) ) )
P:
(P_1) 为 4 :是因为在第一个 ) (数组第4位)前面有4个 (
(P_2) 为 5 :是因为在第二个 ) (数组第6位)前面有5个 (
(P_3) 为 6 :是因为在第三个 ) (数组第8位)前面有6个 (
(后面 (P_4) (P_5) (P_6) 情况跟 (P_3) 是一样的,所以不重复啰嗦了)
W:
(W_i) 表示的是括号数,为了表示清楚一点下面用粗体标清楚
(W_1) 为 1:是因为 ( ( ( ( ) ( ) ( ) ) ) ) 在与第一个 ) 前面的 ( 只形成了 1 个 ( )
((W_2) (W_3) 情况跟 (W_1) 一样)
(W_4) 为 4:是因为 ( ( ( ( ) ( ) ( ) ) ) ) 第 4 个 ) 与数组第 2 位的 ( 配对了,除了它们俩一对外,它们还包含了里面 3 对,所以是 4 对
为什么第 4 个不能与数组第 7 位的 ( 配对?因为第 7 位的已经跟前面的 ) 配对了。
相信看到这里就算没读懂题意的你也有一点开窍了。从第一个 ) 开始,与它最相近的 ( 进行配对,配对之后就不能让后者配对了。所以我们这里可以弄一个bool数组来记录 ( 是否已经配对。
在此之前,我们还要先构造出 S 的字符串,这个构造比较简单,请结合代码思考一下。
随后就遍历一下 S 字符串,再记录一下每个 ) 所对应的答案即可。
数据很小,这种暴力解题没有问题!
// POJ 1068
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int T, n;
int P[25], W[25], pla[25];
char pra[50];
bool take[50];
int main()
{
scanf("%d", &T);
while(T--){
memset(take, false, sizeof(take));
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", &P[i]);
// 构造 S 字符串
int left = 0, i = 0, k = 0;
while(i < n){
if(left == P[i]){
pra[k++] = ')';
i++;
}
else {
pra[k++] = '(';
left++;
}
}
// 记录每个 ) 的位置
int cnt = 0, c = 0;
for(int i = 0; i < n * 2; i++){
if(pra[i] == ')') {
pla[cnt++] = i;
}
}
// 最终遍历找答案
for(int i = 0; i < cnt; i++){
int j = pla[i], ans = 0;
while(j >= 0){
if(pra[j] == '('){
ans++;
if(!take[j]){
W[c++] = ans;
take[j] = true;
break;
}
}
j--;
}
}
for(int i = 0; i < c; i++){
printf("%d%c", W[i], i != c - 1 ? ' ' : '
');
}
}
return 0;
}