题目
问题描述
原来的序列是一个括号序列,此时给出它的压缩序列,
“
(
(
(
(
)
(
(
)
)
)
(
”
“(((()(()))(”
“(((()(()))(”对应的压缩序列是
[
4
,
1
,
2
,
3
,
1
]
[4,1,2,3,1]
[4,1,2,3,1],问在给定压缩序列的前提下,求出匹配序列的个数。
例子:
压缩序列为
[
4
,
1
,
2
,
3
,
1
]
[4,1,2,3,1]
[4,1,2,3,1]时,匹配序列为5,
从第3个到第10个字符的子序列:(()(()))
从第4个字符到第5个字符的子序列:()
从第4个字符到第9个字符的子序列:()(())
从第6个字符到第9个字符的子序列:(())
从第7个字符到第8个字符的子序列:()
分析
这道题的思路就是模拟。
首先分析题目,如果从0开始计数,偶数位置对应的是左括号,奇数位置对应的就是右括号,根据题目,其实我们可以把相邻的位置理解为一个对,比如在压缩序列 [ 4 , 1 , 2 , 3 , 1 ] [4,1,2,3,1] [4,1,2,3,1]中,可以把 [ 4 , 1 ] [4,1] [4,1]理解为一个对,把 [ 2 , 3 ] [2,3] [2,3]理解为另一个对,最后多余的 [ 1 ] [1] [1]是无法找到匹配的,所以舍弃。
接下来我们就处理一下序列 [ [ 4 , 1 ] , [ 2 , 3 ] ] [[4,1],[2,3]] [[4,1],[2,3]]
先处理 [ 4 , 1 ] [4,1] [4,1],4>1,这里只有一种匹配序列,而且 [ 4 , 1 ] [4,1] [4,1]左边没有对了,所以不存在向左边延伸的情况;
再处理
[
2
,
3
]
[2,3]
[2,3],在对内部有两种匹配序列,同时可以发现,在这一对里面多了一个右括号,而且左边仍然有对,所以可以考虑向左边延伸的情况。
想要延伸到左边,就意味着左边的对的左括号数目一定要大于等于右括号才可以相连,然后再考虑左边的对的左括号数目,确定匹配个数,当前左边的对为
[
4
,
1
]
[4,1]
[4,1],如果不使用多余左括号,存在一种匹配序列,在考虑多余左括号,多出3个,但此时
[
2
,
3
]
[2,3]
[2,3]右括号只多出1个,所以接下来还剩一种匹配序列。
之后,不再存在右括号剩余,故不必再左移。
总计5种匹配序列。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1005;
int C[MAXN];
int N;
int main() {
cin>>N;
for(int i=0;i<N;i++){
cin>>C[i];
}
ll cnt = 0;
for (int j = 1; j < N; j += 2) {
ll h = 0;
ll internal = -C[j];
for (int i = j-1; i >= 0; i -= 2) {
h += C[i+1];//总共剩余的右括号
internal += C[i+1];//当前对的右括号
if (C[i] > h) {
cnt += h - internal;
if (internal) ++cnt;
break;
}
if (C[i] >= internal) {
cnt += C[i] - internal;
if (internal) ++cnt;
}
internal -= min((ll)C[i], internal);
h -= C[i];
}
}
cout<<cnt<<endl;
return 0;
}