CF3D题解

https://codeforces.com/problemset/problem/3/D

对于括号串的合法性等价于满足,将(变成1,)变成-1,任意前缀不为负数。

满足一个合法括号串有多种填法,一次调整是将两个不同的括号翻转,我们希望翻转在使结果更优的情况下合法,于是将左边的)和右边的(互换,这样在满足总代价越来越小的同时不影响其他括号。

容易证明最优解是能够被上述调整法到达的

具体做法:

step1 尽可能把)放前面,在满足合法性情况下,先构造一个自由度最高的填法,给到达最优解创造机会。

step2 访问到(,如果总代价更优,考虑和前面的)对调,并且选择最优的调换法,次优和次次优的)在后面依旧有机会对调

记前面为\(pos_i\),后面为\(pos_j\),代价为$ pri$变化为 \(-l[pos_i] + r[pos_i] -r[pos_j] +l[pos_j]\),利用优先队列维护和 \(pos_i\)相关的

#include<bits/stdc++.h>
using namespace std;
const int N = 5e4 + 5;
#define ll long long
string s;
int n;
int p[N],pos[N];
int l[N], r[N];
int turn[N];
int now[N];
ll pri;
//构造初始方案,先全填( ,turn[i]数组计算将'(转换成)的最大数,能转则转
void pre(){
    bool f = 0;
    int tj = 0;
    int w1 = 0, w2 = 0;
    for (int i = 1; i < s.size();i++){
        if(s[i]=='(')tj++,w1++,now[i]=1;
        if(s[i]=='?')tj++;
        if(s[i]==')')tj--,w2++,now[i]=2;
        if(tj<0)f = 1;
        turn[i] = tj / 2;
    }
    if(w1>(s.size())/2 ||w2>(s.size())/2)f = 1;
    for (int i = s.size()-2; i >= 1;i--)
        turn[i] = min(turn[i], turn[i + 1]);
    int tt = 0;
    tj = 0;
    for (int i = 1; i < s.size();i++){
        if(!now[i]){
            if(tt<turn[i])//能转
                now[i] = 2,w2++,tt++,pri+=r[i];
            else
                now[i] = 1, w1++,pri+=l[i];
        }
    }
    if(w1!=w2)
        f = 1;
    if(f){cout << "-1";exit(0);}
}
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> dl;
int main(){
    cin >> s;
    s = " " + s;
    for (int i = 1; i < s.size();i++){
        if(s[i]=='?')
            p[i] = 1,n++,pos[n]=i;
    }
    for (int i = 1; i <= n;i++){
        cin >> l[pos[i]] >> r[pos[i]];
    }
    
    pre();
//  for (int i = 1; i <s.size();i++)
//         cout << now[i];
    //cout << pri << "\n";
    for (int i = 1; i <s.size();i++){//核心算法
        if(s[i]=='?'){
            if(now[i]==2)
                dl.push(make_pair(-r[i] + l[i], i));//可能右移的)
            else{
                if(dl.empty())
                    continue;
                if(dl.top().first-l[i]+r[i]<0){
                    pri += dl.top().first - l[i] + r[i];
                    swap(now[dl.top().second], now[i]);
                    dl.pop();
                    dl.push(make_pair(-r[i] + l[i], i));
                }//如果能调整,选择最优的
            }
        }
    }
    cout << pri << "\n";
    for (int i = 1; i <s.size();i++){
        if(s[i]=='?'){
            if(now[i]==1)
                cout << '(';
            else
                cout << ')';
        }
        else
            cout << s[i];
    }
    return 0;
}
``
posted @ 2026-09-28 19:54  yiyi049  阅读(11)  评论(0)    收藏  举报