zoukankan      html  css  js  c++  java
  • 2017-5-14 湘潭市赛 Parentheses 转化思想+贪心 使括号序列合法的最小花费。满足前面左括号的数量>=有括号的数量。

    Parentheses
    Accepted : 8           Submit : 19
    Time Limit : 3000 MS           Memory Limit : 65536 KB
    
    Parentheses
    
    Bobo has a very long sequence divided into n consecutive groups. The i-th group consists of li copies of character ci where ci 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 di. 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 li,ci,di.
    
        1≤n≤105
        1≤l1+l2+⋯+ln≤109
        l1+l2+⋯+ln is even.
        1≤di≤109
        The sum of n does not exceed 106.
    
    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 
    
    /**
    题目:Parentheses
    链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1266
    题意:从左到右有n个连续的组,每一组有Li个括号,要么全是左括号,要么全是右括号,以及该组的每一个左括号翻成右括号,
    或者右括号翻成左括号的花费Di.可以对这n个组的括号进行翻转,每一个括号都可以选择翻或者不翻,使整个括号序列是一个合法括号序列。
    思路:
    
    我们知道合法括号序列,满足前面左括号的数量>=有括号的数量。前2k个,那么左括号数量>=k个。
    首先把所有左括号翻成右括号,那么所有的括号都变成右括号了。可以先计算花费。然后把那些左括号变成右括号的
    那些Di变成-Di。那么以后再对它进行翻转的时候,相当于一开始就没有翻转。可以抵消原先加上的花费。
    
    从左到右对所有右括号贪心,满足前面左括号的数量>=有括号的数量的这种规则去处理。维护一个堆存储那些可以翻成左括号的位置,
    如果当前需要翻成一个左括号,那么比较当前位置和堆里的,选择一个花费更小的翻成左括号计算花费。同时更新堆。
    
    举个荔枝:
    假设没有组的情况。只是纯粹的若干个括号;
    位置:
     1 2 3 4 5 6 7 8
     ) ) ) ) ) ) ) )
    一开始第一个位置,显然必须翻成左括号,由于堆为空,所以当前翻成左括号。堆仍然为空。
    然后对pos=2处理,此时位置2,应该要至少一个左括号,因为前面pos=1已经翻成左括号了,所以当前这个暂时不用翻成左括号。把它扔进堆里。
    pos=3;至少要有两个左括号,还差一个。堆顶的是pos=2的花费,当前是pos=3的花费。比较花费更小的,把它翻成左括号,然后更新堆。依次处理。
    
    当然题目是分组的:
    
    第一组:把所有右括号更新到堆。然后计算当前这个位置需要多少个左括号,从堆中取出来。
    然后把第二组所有右括号放入堆,然后计算第二组末尾这个位置需要多少个左括号。然后减去原来已经有的左括号数量。
    表示还要多少左括号,从堆中取出。依次处理即可。
    
    
    
    */
    
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> P;
    const int maxn = 1e5+100;
    struct node1
    {
        LL num;
        char ch[2];
        LL cost;
    }a[maxn];
    
    struct node
    {
        LL num;
        LL cost;
        bool operator < (const node&k)const{
            if(cost!=k.cost) return cost>k.cost;///先出小的。
            return num>k.num;
        }
    }t;
    priority_queue<node> qu;
    /// priority_queue<P, vector<P>, greater<P> > qu;
    int main()
    {
        int n;
        while(scanf("%d",&n)==1)
        {
            LL ans = 0;
            for(int i = 0; i < n; i++){
                scanf("%I64d%s%I64d",&a[i].num,a[i].ch,&a[i].cost);
                if(a[i].ch[0]=='('){
                    ans += a[i].num*a[i].cost;
                    a[i].cost = -a[i].cost;
                }
            }
            while(!qu.empty()) qu.pop();
            LL pre = 0, sum = 0, need;
            for(int i = 0; i < n; i++){
                t.num = a[i].num;
                t.cost = a[i].cost;
                qu.push(t);
                sum += a[i].num;
                need = (sum+1)/2;
                need = need - pre;
                pre = (sum+1)/2;
                while(need>0&&!qu.empty()){
                    t = qu.top();
                    qu.pop();
                    if(t.num>need){
                        t.num -= need;
                        qu.push(t);
                        ans += t.cost*need;
                        break;
                    }else
                    {
                        if(t.num==need){
                            ans += t.cost*need;
                            break;
                        }else
                        {
                            need -= t.num;
                            ans += t.cost*t.num;
                        }
                    }
                }
            }
            printf("%I64d
    ",ans);
    
        }
        return 0;
    }
  • 相关阅读:
    IE8 "开发人员工具" 无法使用,无法显示
    Python中用OpenPyXL处理Excel表格
    calendar函数使用说明【转】
    python之fabric2.0模块学习
    Day9
    Day8
    深入super,看Python如何解决钻石继承难题——转自楚门蔡的测视界
    python/socket编程之粘包
    os模块关于目录
    Day7
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/6860906.html
Copyright © 2011-2022 走看看