【贪心】【CF3D】 Least Cost Bracket Sequence

传送门

Description

给一个序列,序列里面会有左括号、问号、右括号。对于一个\(?\)而言,可以将其替换为一个\((\),也可以替换成一个\()\),但是都有相应的代价。问:如何替换使得代价最小。前提是替换之后的序列中,括号是匹配的。如果不能替换为一个括号匹配的序列则输出-1。

Input

第一行是序列,序列长度不超过\(5~\times10^4\),下面m(m是\(m\)的数量)行有每行\(2\)个数据,第一个是\((\)的代价,第2个是\()\)的代价

Output

第一行输出最小代价

第二行输出被转换的序列

Sample Input

(??)
1 2
2 8

Sample Output

4
()()

Solution

显然DP可做,然而数据范围太大。

DP不能就尝试一下贪心。

考虑一个特殊性质:对于一个括号序列,如果想要保证他合法,则必须保证在任意一个位置,其前缀左括号数必须不小于右括号数。否则一定不合法。同时这个条件是括号序列合法的充要条件。于是考虑按照这个性质贪心,对于任意一个可以修改的位置,贪心的修改成右括号。当序列不合法时,贪心选取修改代价最小的位置改成左括号。因为修改左括号不会使序列不合法,所以这个贪心使正确的。

Code

#include<queue>
#include<cstdio>
#include<cstring>
#define rg register
#define ci const int
#define cl const long long int

typedef long long int ll;

namespace IO {
    char buf[90];
}

template<typename T>
inline void qr(T &x) {
    rg char ch=getchar(),lst=' ';
    while(ch>'9'||ch<'0') lst=ch,ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    if(lst=='-') x=-x;
}

template<typename T>
inline void qw(T x,const char aft,const bool pt) {
    if(x<0) x=-x,putchar('-');
    int top=0;
    do {
        IO::buf[++top]=x%10+'0';
        x/=10;
    } while(x);
    while(top) putchar(IO::buf[top--]);
    if(pt) putchar(aft);
}

template<typename T>
inline T mmax(const T a,const T b) {return a > b ? a : b;}
template<typename T>
inline T mmin(const T a,const T b) {return a < b ? a : b;}
template<typename T>
inline T mabs(const T a) {return a < 0 ? -a : a;}

template<typename T>
inline void mswap(T &a,T &b) {
    T temp=a;a=b;b=temp;
}

const int maxn = 50010;

struct M {
    int l,r;
};
M MU[maxn];

struct Zay {
    int pos,v;
    inline bool operator<(const Zay &_others) const {
        return this->v > _others.v;
    }
    Zay (ci _a=0,ci _b=0) {pos=_a,v=_b;}
};

char st[maxn];
std::priority_queue<Zay>Q;

int main() {
    scanf("%s",st+1);
    int l=strlen(st+1);
    if(l&1) return puts("-1")&0;
    for(rg int i=1;i<=l;++i) if(st[i] == '?') {
        qr(MU[i].l);qr(MU[i].r);
    }
    rg int cnt=0;ll _ans=0;
    for(rg int i=1;i<=l;++i) {
        if(st[i] == '(') ++cnt;
        else if(st[i] == ')') --cnt;
        else {
            --cnt;Q.push(Zay(i,MU[i].l-MU[i].r));
            st[i]=')';_ans+=MU[i].r;
        }
        while(cnt<0) {
            if(Q.empty()) return puts("-1")&0;
            int h=Q.top().pos;Q.pop();
            _ans+=MU[h].l-MU[h].r;
            st[h]='(';
            cnt+=2;
        }
    }
    if(cnt > 0) return puts("-1")&0;
    qw(_ans,'\n',true);
    printf("%s",st+1);
    return 0;
}

Summary

可能需要贪心时,寻找题目的特殊性质,按照特殊性质进行贪心。

猜你喜欢

转载自www.cnblogs.com/yifusuyi/p/9806351.html