题目链接:登录—专业IT笔试面试备考平台_牛客网
分析:
这道题目写的时候有一个地方没有想到,就是左边的括号如果还有没有配对的情况,那么他也可以与右边的括号进行配对。
如:( ( ( ( ) (( )) () ) ) )
红色的括号进行配对的情况当时写的时候没有考虑到。
栈:用于存储前面还剩下多少个“ ( ”没有被配对。 因为配对的话," ) "一定是和 最近的" ( "进行配对的。剩下的用栈进行存储,后进先配对。
当在次遇到右括号,那么就将右括号 与 栈顶的‘( ’去进行配对。
当右括号被配对完了,而左括号可以刚好配对玩,或者还没配对完。会有什么样的情况呢?
( ( ( ) )
比如这样的情况
那么这个时候,如果( ( ( ) ) () 这样的时候,
那么就会有( ( ) ) , () , ( ( ) ) ()就说明后面新配对的 (),与前面那个右括号配对完的情况,可以恰好组成一组。
在比如:
() (( )(( () () )) )
而这个红色的就会与(( )) 可以与( )的进行匹配,( ) 可以与()进行连续的匹配。
而这个就可以通过DP进行统计。
代码实现:
# include <iostream>
# include <stack>
using namespace std;
const int N = 1e6 + 10;
/*
如果多出来了左括号,可能后面会有右括号可以与其进行匹配,
但是如果前面多出来了右括号,
那么后面多出来的左括号和右括号都没有用,不能组成成立的情况
*/
long long f[N]; // 后面的偶数项,可以与前面多少个进行配对
long long a[N];
stack<pair<long long,long long> > q; //q.first为左括号节点的下标 以及个数
long long n;
int main()
{
scanf("%lld",&n);
for(int i = 1 ; i <= n ;i++)
{
scanf("%lld",&a[i]);
}
long long ans = 0; //答案
for(int i = 1 ; i <= n ; i++)
{
if(i % 2) // 左括号
{
q.push({i,a[i]}); // 将左括号的下标和左括号个数存入
}
else // 右括号,那么和左边剩下来的左括号进行匹配。两个情况,1.要么左边括号全部匹配掉了,剩下右括号,那么这个右括号没有用。2.剩下左括号,右括号被匹配完了,那么左括号还可以继续用
{
if(a[i] == 0) // 此题不需要,因为此题要求a[i]都 > 0 ,但如果a[i]可以等于0的话,那么就需要加这句话,因为后面的f[i] = f[last] + 1 是在a[i] == 0,且原a[i]右括号是可以组合成功的时候才满足f[i] = f[last] + 1的,如果a[i]原来就等于0,那么这是不满足组合情况的,这个地方就得断开,所以f[i]必定为0
{
continue;
}
long long last = 0; //最后一个将右括号完全匹配的左括号的下标 - 1,用于后面f[i] 用 f[last]进行更新
while(q.size()) // 栈中的左括号,从最后的左括号向最旧的左括号,不断的去与右括号匹配
{
auto temp = q.top();
long long idx = temp.first; // 左括号位置下标
long long v = temp.second; // 这个位置的左括号个数
q.pop();
if(v <= a[i]) //如果当前这个左括号比右括号少,那么还可以继续匹配
{
ans += v; // 左括号与右括号单独匹配的个数
a[i] -= v; // 剩下右括号数
ans += f[idx - 1]; // 这个f[idx - 1]的含义就是,前面可以与i匹配成功
//idx的左括号可以与i的右括号匹配,那么f[idx - 1]统计的则是前面已经匹配成功的个数。可以构成这么多个子串
last = idx - 1; // 最后匹配成功的左括号的下标 - 1
}
else // 左边括号有剩余,并且当前这个左括号下标对应的左括号也还有剩余,所以不可能构成别的新的连续满足条件的序列,所以last = 0
{
ans += a[i];
v -= a[i]; // 剩余左括号的数
a[i] = 0;
last = 0; // 当前这个位置都还有左括号,无法向左边构成新的子序列。
q.push({idx,v}); //重新压栈
}
if(a[i] == 0)
{
break;
}
}
if(a[i] == 0) // 右括号被匹配完了,说明左括号成立
{
f[i] = f[last] + 1; // 左边最last的情况 + 1.
}
// 而a[i] > 0 则说明还有右括号,没用
}
}
printf("%lld\n",ans);
return 0;
}
/*
如果a[]值可以为0
数据:
4
1 0 1 2
结果为:2
*/