题面

确实是原题 BZOJ3838
题解
考虑 模拟费用流(显然跑费用流铁定 TLE ,故这里只是 模拟 ,来发现其本质在干哈):
考虑建图:
- 建 n 个点 ,∀i∈[1,n),i→i+1 连边容量 +∞ 费用 0。
- 建源汇点 s′,t ,对于所有
(
,s′→i 容量 1,费用为该位置代价; 对于所有 )
,i→t 容量 1,费用为该位置代价
- 实际源点 s 向 s′ 连边,容量为 k/2,费用为 0
以上建图正确性显然,跑最小费用最大流就完事了,现在来考虑以下这实际在干嘛。

在做费用流时,每次最短路增广一单位流量,如上图 橙/绿 线就是一次合法增广。对于一次增广,如橙线经过的两端点 a,b 就是这次选中的括号,显然是一个左括号一个右括号。再考虑这个图上增广路不可能从 s′ 出去再绕到 s′ ,也就是说之前某次增广 s→u 的流量不会退回来:某个括号被选中后就不会删除了。
再考虑增广路有几种情况:
- 如橙线,左括号在右括号左边,a→b 路径上边权都是 +∞ 显然合法,且给 a,b 间反向边都加一
- 如绿线,左括号在右括号右边,这时候就有限制了,需要 c,d 间反向边都为正。且增广后给这些反向边都减一
总结以下,需要干如下的事情:
找一个左括号,一个右括号,使其代价和最小,并有限制:( 即有一个长度为 n−1 的序列 S ,初始都为零 )
- 若左括号在右括号左边:无限制,取了之后 S[l…r−1] 区间加一
- 若左括号在右括号右边:需要 mini∈[l,r−1]Si>0 ,取了之后 S[l…r−1] 区间减一
然后这玩意儿变得很 simple ,我们用线段树维护即可。
其实也挺毒瘤的,线段树上要维护九个值。具体的:
需要维护 S 的区间 min ,支持区间加减
先考虑左括号在右括号左:
维护区间最小代价左括号 mnL,区间最小代价右括号 mnR ,区间最小代价括号对 mnLR ,合并的时候显然
mnLxmnRxmnLRx=min(mnLls,mnLrs)=min(mnRls,mnRrs)=min(mnLRls,mnLRrs,mnLls+mnRrs)
再考虑左括号在右括号右,这种情况有限制,需要两括号间 s 都大于零,于是我们维护两套信息,一套假设区间 min>0 一套假设区间 min=0 。
对于前者,我们只要和上面的一样维护即可,对于后者,考虑合并的时候两括号区间内 Si>0 ,那么 mnL′ 维护左端开始不经过区间 min 位置的最小代价左括号,mnR′ 从右端开始不经过 min 位置的的最小代价右括号。
考虑合并,需要分讨:
若 minls=minrs ,即假设区间 min=0 ,两边都有零。
mnLls′⋯⋯0⋯0mnRls′⋯mnLrs′⋯0⋯mnRrs′⋯⋯
零的位置随便标的,没有关系,考虑 mnRLx′ 除了合并两孩子内的,还可以等于 mnRls′+mnLrs′ ,此外还可以发现 mnLx′=mnLls′,mnRx′=mnRrs′
若 minls=minrs,有两种情况,这里只讨论左小于右(右小于左同理)
mnLls′⋯⋯0⋯0mnRls′⋯mnLrs,mnRrs⋯⋯⋯⋯
此时只可能左边有零,右边是没有限制的,可以发现:
mnRLx′=min(mnRLls′,mnRLrs,mnRls′+mnLrs)
mnLx′=mnLls′,mnRx′=min(mnRrs,mnRls′)
然后就完事了,注意以上维护的都是下标,为了方便建议重载运算符。每次找最小的括号对,若 min=0 取 mnRL′ ,不然取 mnRL。mnLR 无论如何都可以取。然后把对应两括号下标 p1,p2 代价改为 +∞ ,并对 [p1,p2−1] 进行区间加减,注意 [p1,p2−1] 而不是 [p1,p2] 。
然后真的结束了
CODE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
| #include <cstdio> #include <cstdlib> #include <cstring> #define _mn(X) gmin(X[ls],X[rs]) template <typename T> inline void red(T &x) { x=0;bool f=0;char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') f^=1; ch=getchar();} while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(T)(ch^48),ch=getchar(); if(f) x=-x; } using namespace std; typedef long long ll; const int N = 2000010; const int inf = 0x3f3f3f3f; char s[N]; int a[N],n,K; struct dat{ int p1,p2; dat(){} dat(int _p1,int _p2):p1(_p1),p2(_p2) {} }; inline int gmin(int x,int y) {return (a[x]<a[y])?x:y;} inline dat gmin(dat x,dat y) {return (a[x.p1]+a[x.p2]<a[y.p1]+a[y.p2])?x:y;} namespace segtree { #define ls (x<<1) #define rs (x<<1|1) #define mid ((l+r)>>1) int mn[N<<2],tag[N<<2]; int mnL[N<<2],mnR[N<<2],_mnL[N<<2],_mnR[N<<2]; dat mnLR[N<<2],_mnRL[N<<2],mnRL[N<<2]; void pushup(int x) { mn[x]=(mn[ls]<mn[rs])?mn[ls]:mn[rs]; mnL[x]=_mn(mnL); mnR[x]=_mn(mnR); mnLR[x]=gmin(_mn(mnLR),dat(mnL[ls],mnR[rs])); mnRL[x]=gmin(_mn(mnRL),dat(mnR[ls],mnL[rs])); if(mn[ls]==mn[rs]) { _mnL[x]=_mnL[ls]; _mnR[x]=_mnR[rs]; _mnRL[x]=gmin(_mn(_mnRL),dat(_mnR[ls],_mnL[rs])); }else { if(mn[ls]<mn[rs]) { _mnL[x]=_mnL[ls]; _mnR[x]=gmin(_mnR[ls],mnR[rs]); _mnRL[x]=gmin(gmin(_mnRL[ls],mnRL[rs]),dat(_mnR[ls],mnL[rs])); }else { _mnL[x]=gmin(mnL[ls],_mnL[rs]); _mnR[x]=_mnR[rs]; _mnRL[x]=gmin(gmin(mnRL[ls],_mnRL[rs]),dat(mnR[ls],_mnL[rs])); } } } inline void updata(int x,int vl) { mn[x]+=vl; tag[x]+=vl;} inline void pushdown(int x) { if(tag[x]==0) return ; updata(ls,tag[x]); updata(rs,tag[x]); tag[x]=0; } void modify(int L,int R,int vl,int l=1,int r=n,int x=1) { if(L<=l&&r<=R) return updata(x,vl); pushdown(x); if(L<=mid) modify(L,R,vl,l,mid,ls); if(R>mid) modify(L,R,vl,mid+1,r,rs); pushup(x); } void del(int p,int l=1,int r=n,int x=1) { if(l==r) { mnL[x]=mnR[x]=_mnL[x]=_mnR[x]=0; a[l]=inf; return ; } pushdown(x); if(p<=mid) del(p,l,mid,ls); else del(p,mid+1,r,rs); pushup(x); } void build(int l=1,int r=n,int x=1) { if(l==r) { mnL[x]=(s[l]=='(')?l:0; mnR[x]=(s[l]==')')?l:0; _mnL[x]=_mnR[x]=0; return ; } build(l,mid,ls); build(mid+1,r,rs); pushup(x); } } using namespace segtree;
int main() { scanf("%s",s+1);s[0]='+'; n=strlen(s+1); a[0]=inf; for(int i=1;i<=n;++i) red(a[i]); build(); red(K); if(K&1) printf("-1\n"); else { ll ans=0; for(int ts=1;ts<=K/2;++ts) { dat A=mnLR[1]; if(mn[1]==0) A=gmin(A,_mnRL[1]); else A=gmin(A,mnRL[1]); if(A.p1==0||A.p2==0||a[A.p1]==inf||a[A.p2]==inf) { puts("-1"); return 0; } ans+=a[A.p1]+a[A.p2]; if(s[A.p1]=='(') modify(A.p1,A.p2-1,1); else modify(A.p1,A.p2-1,-1); del(A.p1); del(A.p2); } printf("%lld\n",ans); } }
|