题目大意:
对于一个良好组织的圆括号字符串S,有两种编码方式:
P方式:
P = p1 p2 … pn,这里pi是第i个右圆括号之前左圆括号的数量
W方式
W = w1 w2 … wn,这里举个例子,比如S中第i个右圆括号a,我们记录这个整数:从与a匹配的左圆括号数起,到a为止,中间右圆括号的数量。
要求从P编码转到W编码
方法一:
由p序列构造出字符串s,再由s得出w序列
遍历数组,依次找出每个‘)’,然后从当前位置逆向查找,如果找到了一个‘(’,我们需要判断该‘(’是否已经配对,配对信息用used数组记录,如果已经配对,则说明该‘(’已经对应了一个‘)’,结果加1,否则该‘(’与‘)’配对,匹配找到,退出循环。
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
string PtoS(int n, int *p){
int count = 0;
string s = "";
for(int i = 0; i < n; i++){
while(count < p[i]){
s += '(';
count++;
}
s += ')';
}
return s;
}
void StoW(int n, string s){
int used[2*n];
int w[n+2];
int pos = 0;
memset(used, 0, sizeof(used));
memset(w, 0, sizeof(w));
for(int i = 0; i < 2*n; i++){
if(s[i] == ')'){
for(int j = i-1; j >= 0; j--){
if(s[j] == '('){
if(used[j] == 1)
w[pos]++;
else{
++w[pos];
printf("%d", w[pos]);
if(i != 2*n -1)
printf(" ");
++pos;
used[j] = 1;
break;
}
}
}
}
}
printf("\n");
return;
}
int main(){
//freopen("tmp.txt", "r", stdin);
int t, n;
scanf("%d", &t);
while(t--){
scanf("%d", &n);
int p[n];
for(int i = 0; i < n; i++){
scanf("%d", &p[i]);
}
string parent = PtoS(n, p);
StoW(n, parent);
}
}
方法二:
由于括号序列是完全匹配的
所以有多少右括号就有多少左括号
P序列输入的是每一个右括号前左括号的个数
要求的是从与他匹配的左括号开始到他自身的右括号的个数
所以可以设一个左括号序列用右括号跟他匹配
对于每一个P
他的左边肯定有p个左括号
跟他匹配的就是从第p个开始的往前数第一个未被匹配的左括号
找到后标记一下
而从这个左括号开始到p的右括号的个数正好就是他们之间已经匹配的括号对数+1
具体做法如下
用一个数组left[]记录左括号的匹配情况
初始化为零表示都没有匹配
然后读入一个p就从left[p]开始查找第一个left[j]==0
然后p-j+1就是从与他匹配的左括号到他自身的右括号的个数
最后把left[j]赋值为1表示已经匹配成功
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
int main(){
//freopen("tmp.txt", "r", stdin);
int left[25], i, first, t, n, p;
scanf("%d", &t);
while(t--)
{
memset(left,0,sizeof(left));
first=1;
scanf("%d", &n);
while(n--)
{
scanf("%d", &p);
i = p;
while(left[i]) i--;
if(first){
printf("%d", p-i+1);
first=0;
}
else printf(" %d", p-i+1);
left[i]=1;
}
printf("\n");
}
return 0;
}