CF3D 两层别墅

· · 题解

题意:给一个字符集为 \{\texttt(,\texttt?,\texttt)\} 的偶数长度字符串 s,每个问号 s_i 有将其修改为左括号的代价 l_i 和修改为右括号的代价 r_i。你需要用最少代价将 s 改成一个合法括号序列 s'。输出代价和 s‘ 或报告无解。

先上括号序列的经典套路:( 视作 +1) 视作 -1,序列合法当且仅当所有前缀和非负且整体和为 0。再上一个括号序列经典(?)贪心策略:先把所有的改成 (,如果最小前缀和为负则无解,然后在保证可能合法(即最小前缀和非负)的情况下一个一个改成 ),如果最后整体和不为 0 则无解,否则输出答案。最小前缀和可用线段树维护。对于本题来说,策略就是将括号按照 r_i-l_i 大到小排序,如果能改就改成 )

接下来是策略的正确性证明。记我们改出来的方案为 a,随便一种另外的方案为 t。一定能找到最左边的 p 使得 a_p=\texttt),t_p=\texttt(,以及最左边的 q 使得 a_q=\texttt(,t_q=\texttt)。首先,如果 t_pt_q 能互换,根据我们的贪心策略,这一定是不劣的。如果 q<p,说明我们需要把 t 里的一个 )...( 改成 (...),改完之后每个前缀和都不减少,一定合法。

否则,p<q,如下图,因为 p 是最左边的所以 t_{[1,p)}=a_{[1,p)},令 S(q) 表示 q 的整体和,则 S(t_{[1,p]})=S(a_{[1,p]})-S(a_p)+S(t_p)=S(a_{[1,p]})+2。因为 q 也是最左边的,所以如果有 r\in(p,q) 满足 a_r\neq t_r 那一定是 a_r=\texttt),t_r=\texttt(,所以有了这个证明最关键(?)的结论:\forall i\in(p,q):S(t_{(p,i]})\ge S(a_{(p,i]})。可以推出 \forall i\in(p,q):S(t_{[1,i]})=S(t_{[1,p]})+S(t_{(p,i]})\ge2+S(a_{[1,p]})+S(a_{(p,i]})\ge2。这么改之后,对于任意的 i\in[p,q)S(t_{[1,i]}) 都会减少 2,但是原本就 \ge 2,所以这么改是合法的。

注意不能直接说「因为 a 合法,所以 t 这么一改一定合法」,因为 ta 可能还有其他不同,这么证明不严谨。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/exception.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/list_update_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
// using namespace __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>T;
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef long double ldb;
//#define umap unordered_map
#define umap __gnu_pbds::cc_hash_table
#define mkp make_pair
#define prque priority_queue
#define emp emplace
#define empb emplace_back
#define empf emplace_front
#define invarg invalid_argument
#define cus_throw(msg) throw invarg(string(msg) + " at " + __FILE__ + ":" + to_string(__LINE__))
random_device rndv;
mt19937 rd(rndv());
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const vector<ll> millerrabin = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
const double eps = 1e-8;
inline void enter(){putchar('\n');}
inline void space(){putchar(' ');}
inline ll readll(){ll ret=0,k=1;char c;do{c=getchar();if(c=='-'){k=-1;}}while(('0'>c)|('9'<c));do{ret=(ret<<3)+(ret<<1)+c-48;c=getchar();}while(('0'<=c)&(c<='9'));return ret*k;}
inline void read(ll&x){x=readll();}
inline char readchar(){char ret;do{ret=getchar();}while(ret<=32);return ret;}
inline void read(char&x){x=readchar();}
inline string readstr(){string ret;char c;do{c=getchar();}while(c<=32);do{ret+=c;c=getchar();}while((c>32)&(c!=EOF));return ret;}
inline void read(string&x){x=readstr();}
inline void write(ll x){if(!x){putchar('0');return;}if(x<0){putchar('-');x*=-1;}char op[20]={};ll cur=0;while(x){op[++cur]=x%10+48;x/=10;}while(cur){putchar(op[cur--]);}}
inline ostream& operator<<(ostream& out, __int128 x){if(!x){out<<"0";return out;}if(x<0){out<<"-";x*=-1;}char op[40]={};ll cur=0;while(x){op[++cur]=x%10+48;x/=10;}while(cur){out<<op[cur--];}return out;}
// -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

namespace modint {
    const ll MOD = 1;
    struct modint {
        ll val, mod;
        void setmod(ll x) {
            mod = x;
        }
        explicit operator ll() {
            return val;
        }
        modint() {
            val = 0, mod = MOD;
        }
        modint(ll v, ll m = MOD) {
            if (m == 1) {
                cus_throw("init modint without mod");
            }
            v %= m;
            if (v < 0) {
                v += m;
            }
            val = v;
            mod = m;
        }
    };
    #define chkmod(x, y) if (x.mod != y.mod) cus_throw("mod isn't the same")
    modint operator+(modint x, modint y) {
        chkmod(x, y);
        return modint(x.val + y.val, x.mod);
    }
    modint operator-(modint x, modint y) {
        chkmod(x, y);
        return modint(x.val - y.val, x.mod);
    }
    modint operator*(modint x, modint y) {
        chkmod(x, y);
        return modint(__int128(1) * x.val * y.val, x.mod);
    }
    modint qpow(modint x, ll y) {
        if (!y) {
            return modint(1, x.mod);
        } else if (y & 1) {
            return x * qpow(x, y ^ 1);
        } else {
            return qpow(x * x, y >> 1);
        }
    }
    modint inv(modint x) {
        return qpow(x, x.mod - 2);
    }
    modint operator/(modint x, modint y) {
        chkmod(x, y);
        if (ll(y) == 0) {
            cus_throw("modint divide by 0");
        }
        return x * inv(y);
    }
    modint operator+=(modint& x, modint y) {
        return x = x + y;
    }
    modint operator-=(modint& x, modint y) {
        return x = x - y;
    }
    modint operator*=(modint& x, modint y) {
        return x = x * y;
    }
    modint operator/=(modint& x, modint y) {
        return x = x / y;
    }
    bool operator==(modint x, modint y) {
        chkmod(x, y);
        return x.val == y.val;
    }
}

const ll MAXN = 5e4 + 5;

string s;
ll lb[MAXN], rb[MAXN], n, iq[MAXN], qc;

namespace segtree {
    struct sec {
        ll sum = 0, mnp = inf;
        explicit operator ll() {
            return mnp;
        }
    };
    sec operator+(sec x, sec y) {
        sec r;
        r.sum = x.sum + y.sum;
        r.mnp = min(x.mnp, x.sum + y.mnp);
        return r;
    }
    struct segtree {
        ll size;
        sec val[MAXN << 2];
        #define l(x) (x<<1)
        #define r(x) ((x<<1)|1)
        #define mid ((lx+rx)>>1)
        #define lpr l(x),lx,mid
        #define rpr r(x),mid+1,rx
        #define prl ll x, ll lx, ll rx
        void init(ll x) {
            size = 1;
            while (size < x) size <<= 1;
        }
        void psu(ll x) {
            val[x] = val[l(x)] + val[r(x)];
        }
        void mdf(ll p, ll v, prl) {
            if (p < lx || rx < p) {
                return;
            }
            if (p == lx && lx == rx) {
                val[x].mnp = val[x].sum = v;
                return;
            }
            mdf(p, v, lpr), mdf(p, v, rpr), psu(x);
        }
        void mdf(ll p, ll v) {
            mdf(p, v, 1, 1, size);
        }
        sec qry(ll l, ll r, prl) {
            if (r < lx || rx < l) {
                return sec();;
            }
            if (l <= lx && rx <= r) {
                return val[x];
            }
            return qry(l, r, lpr) + qry(l, r, rpr);
        }
        sec qry(ll l, ll r) {
            return qry(l, r, 1, 1, size);
        }
    } st;
}

map<char, ll> cv;
ll ans = 0;

int main() {
    cv['('] = cv['?'] = 1;
    cv[')'] = -1;
    read(s);
    n = s.size();
    for (ll i = 0; i < n; ++i) {
        if (s[i] == '?') {
            iq[++qc] = i + 1;
        }
    }
    s = '.' + s;
    for (ll i = 1; i <= qc; ++i) {
        read(lb[iq[i]]), read(rb[iq[i]]);
    }
    segtree::st.init(n);
    for (ll i = 1; i <= n; ++i) {
        segtree::st.mdf(i, cv[s[i]]);
    }
    if (ll(segtree::st.qry(1, n)) < 0) {
        puts("-1");
        return 0;
    }
    vector<ll> a;
    for (ll i = 1; i <= n; ++i) {
        if (s[i] == '?') a.empb(i);
    }
    sort(a.begin(), a.end(), [](ll x, ll y)->bool {return mkp(rb[x] - lb[x], x) < mkp(rb[y] - lb[y], y);});
    for (ll i : a) {
        segtree::st.mdf(i, -1);
        if (ll(segtree::st.qry(1, n)) < 0) {
            segtree::st.mdf(i, 1);
            s[i] = '(';
            ans += lb[i];
        } else {
            s[i] = ')';
            ans += rb[i];
        }
    }
    ll pre = 0;
    for (char c : s) {
        pre += cv[c];
    }
    if (pre > 0) {
        puts("-1");
        return 0;
    }
    write(ans), enter(), puts(s.c_str() + 1);
    return 0;
}

;             ;;;;;;;;          ;
;                   ;          ; ;
;                  ;          ;   ;
;                 ;          ;     ;
;                ;          ;;;;;;;;;
;               ;          ;         ;
;              ;          ;           ;
;;;;;;;;;;;   ;;;;;;;;   ;             ;

   ;                        ;
  ;                          ;
 ;                            ;
;                              ;
;                              ;
;                              ;
 ;                            ;
  ;         ;;          ;;   ;
   ;        ;;          ;;  ;