JZOJ6716. 【2020.06.07省选模拟】反讽

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);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_43649416/article/details/106724859