Codeforces 1556 C. Compressed Bracket Sequence(1800)

链接:https://codeforces.com/contest/1556/problem/C

题意:

原来的序列是一个括号序列,此时给出它的压缩序列,“ ( ( ( ( ) ( ( ) ) ) ( ” 对应的压缩序列是[4,1,2,3,1],问在给定压缩序列的前提下,求出合法子序列的个数。

题解:

PS:合理括号序列一定有 ‘(’和‘)’的数量相同且任意时候‘(’的数量一定比‘)’多;

因为输入是成对出现的所以我们可以拆开一对一对看,对于单独的每一对,合法的数量就是取决于两值较小的那个,再看对与对之间会出现什么情况,对与对之间可能会连接在一起构造出合法序列,()那就要模拟这个过程;

拿第二组案例来说

6
1 3 2 1 2 4

构造出来的序列为“()))(()(())))”,一共有三对,分别是[1,3],[2,1],[2,4];

对第一对处理,自身可以构造1,左边没有对,所以ans+=1;

对第二对处理,自身可以构造1,因为之前左括号的数量大于右括号的数量所以不能向左延伸,所以ans+=1;

对第三对处理,自身可以构造2,因为多了两个右括号,所以可能向左延伸,左边原本有一对所以ans先加一,而且左边那对有多余的1个左括号可以消耗一个右括号去匹配ans再加1,再看能不能继续向左延伸,发现加上后,右括号的数量比左括号多,所以这一对跳过;

总计ans=6;

具体模拟过程看代码;

代码:

有注释:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int num[10005];
int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> num[i];
    }
    ll cnt = 0;
    for (int i = 1; i < n; i += 2)
    {
        ll x = 0;
        ll temp = -num[i];
        for (int j = i - 1; j >= 0; j -= 2)
        {
            x += num[j + 1];//总共右括号数量
            temp += num[j + 1];//当前对,多余的右括号数
            if (num[j] > x)//如果当前左括号比所有的右括号都多,答案加自身的可以构造的,如果能连上再加1,并且因为已经断了所以不再向左延伸
            {
                cnt += (x - temp);
                if (temp > 0)//有多余的说明可以连上,要算上连上后的1;
                {
                    cnt++;
                }
                break;
            }
            if (num[j] >= temp)//如果当前左括号比当前的多余的右括号多,答案加自身的可以构造的,如果能连上再加1,向左延伸
            {
                cnt += (num[j] - temp);//消耗掉多余的以后,剩下的就是可以独立构造的
                if (temp > 0)//有多余的说明可以连上,要算上连上后的1;
                {
                    cnt++;
                }
            }
            temp -= min(ll(num[j]), temp);//表示当前对亏几个右括号
            x -= num[j];//消耗的右括号的数量相当于当前的左括号的数量,所有直接减去当前左括号的数量
        }
    }
    cout << cnt << endl;
    return 0;
}

无注释:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int num[10005];
int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> num[i];
    }
    ll cnt = 0;
    for (int i = 1; i < n; i += 2)
    {
        ll x = 0;
        ll temp = -num[i];
        for (int j = i - 1; j >= 0; j -= 2)
        {
            x += num[j + 1];
            temp += num[j + 1];
            if (num[j] > x)
            {
                cnt += (x - temp);
                if (temp > 0)
                {
                    cnt++;
                }
                break;
            }
            if (num[j] >= temp)
            {
                cnt += (num[j] - temp);
                if (temp > 0)
                {
                    cnt++;
                }
            }
            temp -= min(ll(num[j]), temp);
            x -= num[j];
        }
    }
    cout << cnt << endl;
    return 0;
}

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值