Description
T < = 10 ; n , m < = 1 e 6 T<=10;n,m<=1e6 T<=10;n,m<=1e6
Solution
- 一个常见的贪心模型,首先选了一段-1就一定要选连续的+1.
- 考虑一个完全加强版,给一棵树的限制,每一条边(a,b)表示先-a,然后会有+b的收益,父亲边选了儿子才能选,当前的钱非负。
- 考虑如果没有限制,那么收入为正的一定比收入为负的优。收入同时为正,限制小的优。收入同时为负,考虑反过来,那么就变成(b,a),那么b为限制,同理反过来,限制大的优。可知选了父亲就一定会选它,那么将它和它的父亲合并即可。
- 或者可以换一种理解方法,设定优劣是相对它的前一个而言的,优劣性可以根据上面的贪心得到,那么如果选了一个劣的,就一定要把后面的优于它的选了,所以可以合并。动态合并,用一个栈来维护即可。然后对于两条链贪心即可。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 1000005
using namespace std;
int T,n,m,i,j,k,a[maxn],b[maxn],ans;
int tot1,A[maxn][2],tot2,B[maxn][2];
int d1[maxn],d2[maxn];
int cmp(int a1,int b1,int a2,int b2){
int t1=b1>=0,t2=b2>=0;
if (t1!=t2) return t2>t1;
if (t1==1) return a2<=a1;
if (t1==0) return a1+b1<=a2+b2;
}
int main(){
freopen("ceshi.in","r",stdin);
// freopen("irony.in","r",stdin);
// freopen("irony.out","w",stdout);
scanf("%d",&T);
while (T--){
scanf("%d%d",&n,&m),a[0]=b[0]=-1;
char ch=getchar(); while (ch!='('&&ch!=')') ch=getchar();
int pre0=0,pre1=0; tot1=tot2=0;
for(i=1;i<=n;i++) {
a[i]=(ch=='(')?1:-1,ch=getchar();
if (a[i]!=a[i-1]) {
if (a[i]==1) pre1++; else {
if (pre0||pre1)
tot1++,A[tot1][0]=pre0,A[tot1][1]=pre1-pre0;
pre0=1,pre1=0;
}
} else if (a[i]==1) pre1++; else pre0++;
}
if (pre0||pre1) tot1++,A[tot1][0]=pre0,A[tot1][1]=pre1-pre0;
while (ch!='('&&ch!=')') ch=getchar();
pre0=pre1=0;
for(i=1;i<=m;i++) {
b[i]=(ch=='(')?1:-1,ch=getchar();
if (b[i]!=b[i-1]) {
if (b[i]==1) pre1++; else {
if (pre0||pre1)
tot2++,B[tot2][0]=pre0,B[tot2][1]=pre1-pre0;
pre0=1,pre1=0;
}
} else if (b[i]==1) pre1++; else pre0++;
}
if (pre0||pre1) tot2++,B[tot2][0]=pre0,B[tot2][1]=pre1-pre0;
d1[0]=d2[0]=0;
for(i=1;i<=tot1;i++){
d1[++d1[0]]=i;
while (d1[0]>1&&cmp(A[d1[d1[0]-1]][0],A[d1[d1[0]-1]][1],A[d1[d1[0]]][0],A[d1[d1[0]]][1])){
int x=d1[d1[0]-1],y=d1[d1[0]];
A[x][0]=max(A[y][0]-A[x][0]-A[x][1],0)+A[x][0];
A[x][1]+=A[y][1];
d1[0]--;
}
}
for(i=1;i<=tot2;i++){
d2[++d2[0]]=i;
while (d2[0]>1&&cmp(B[d2[d2[0]-1]][0],B[d2[d2[0]-1]][1],B[d2[d2[0]]][0],B[d2[d2[0]]][1])){
int x=d2[d2[0]-1],y=d2[d2[0]];
B[x][0]=max(B[y][0]-B[x][0]-B[x][1],0)+B[x][0];
B[x][1]+=B[y][1];
d2[0]--;
}
}
int now=0; ans=0; int t0=1,t1=1;
while (t0<=d1[0]||t1<=d2[0]){
i=d1[t0],j=d2[t1];
if ((t0>d1[0]||!cmp(B[j][0],B[j][1],A[i][0],A[i][1]))&&t1<=d2[0]){
if (now<B[j][0]) ans+=B[j][0]-now,now=B[j][0];
now+=B[j][1],t1++;
} else {
if (now<A[i][0]) ans+=A[i][0]-now,now=A[i][0];
now+=A[i][1],t0++;
}
}
printf("%d\n",ans+now);
}
}