湘潭邀请赛G- Parentheses(贪心,思维)

Parentheses

Bobo has a very long sequence divided into n  consecutive groups. The i  -th group consists of l i   copies of character c i   where c i   is either "(" or ")".

As the sequence may not be valid parentheses sequence, Bobo can change a character in the i  -th group from "(" to ")" (and vice versa) with cost d i   . He would like to know the minimum cost to transform the sequence into a valid one.

Note:

  • An empty string is valid.
  • If S  is valid, (S)  is valid.
  • If U,V  are valid, UV  is valid.

Input

The input contains zero or more test cases and is terminated by end-of-file. For each test case:

The first line contains an integer n  . The i  -th of the following n  lines contains l i ,c i ,d i   .

  • 1n10 5  
  • 1l 1 +l 2 ++l n 10 9  
  • l 1 +l 2 ++l n   is even.
  • 1d i 10 9  
  • The sum of n  does not exceed 10 6   .

Output

For each case, output an integer which denotes the result.

Sample Input

4
1 ( 1
1 ( 2
1 ( 3
1 ) 4
2
500000000 ) 1000000000
500000000 ( 1000000000

Sample Output

2
500000000000000000

Note

For the first sample, Bobo should change only the character in the second group.

For the second sample, Bobo should change half of characters in both groups.


Source

XTU OnlineJudge 

思路:

这道题一开始想的,思路很乱,就是不知道什么时侯该吧左括号变为右括号,什么时候把右括号变为左括号,要考虑道后面出现的情况,后面根据题解的启发,我想到可以,先把右括号变为左括号,根据括号总和和左括号数来决定,左括号的数要大于等于(sum+1)/2为什么要sum+1呢,当sum为奇数时,比如7,这时如果不是sum+1的话,那么左括号的个数为3,然后总数加一的话,新加入的·一组如果话费更小了的话,那么选择的话是后面加入进来的,而不是前面的,就是错了,将右括号变为左括号后,然后在将多余的左括号变为右括号,但是这样做的话会存在一个很麻烦的地方,就是到第二次扫的时候,也就是将多余的右括号变为左括号的时候,要记录上一次什么地方改变了,因为有可能一组中没有全部变完,也可能全部变完,记录的时候会很麻烦,所以我们可以考虑这种做法,一开始把所有的左括号变为右括号,然后把花费取相反数,这样的话就只用扫一次了,不用记录哪个位置变成什么了,然后用一个优先队列维护一下,当前最小花费就行了(优先队列好像不能只重载大于号)


ac代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<sstream>
#include<queue>
#define LL long long
using namespace std;
const int maxn = 1e5+10000;
struct node
{
    LL num,cost;
    char m[2];
    bool operator < (const node &p) const
    {
        return this->cost>p.cost;
    }
}t[maxn];
int n;

int main()
{
    while(~scanf("%d",&n))
    {priority_queue<node>Q;
    LL pre = 0 , sum = 0,ans = 0;
        for(int i = 1 ;i<=n;i++)
        {
            scanf("%I64d%s%I64d",&t[i].num,t[i].m,&t[i].cost);
            if(t[i].m[0]=='(')
            {
                t[i].m[0]=')';
                ans+=t[i].cost*t[i].num;
                t[i].cost = -t[i].cost;
            }
        }
        while(!Q.empty()) Q.pop();

        for(int i = 1 ;i <= n;i++)
        {
            sum += t[i].num;
                Q.push(t[i]);
            LL need  = (sum+1)/2 - pre;
            if(need>0)
            {
                while(!Q.empty()&&need)
                {
                    node tmp = Q.top();
                    Q.pop();
                    if(need>=tmp.num)
                    {
                        need -= tmp.num;
                        ans += tmp.num*tmp.cost;
                        pre+=tmp.num;
                        //Q.pop();
                    }
                    else
                    {

                        tmp.num -= need;
                        pre+=need;
                        ans += need*tmp.cost;
                        Q.push(tmp);
                          need = 0;
                    }
                }
            }
        }
        cout<<ans<<endl;
        //cout<<pre<<' '<<sum/2<<endl;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值