首页 > 其他分享 >P3215 [HNOI2011]括号修复题解

P3215 [HNOI2011]括号修复题解

时间:2023-02-05 23:33:54浏览次数:42  
标签:lmx right rs 题解 P3215 HNOI2011 ls rmi left

发现题解里的维护前后缀最大最小值的做法都是感性理解,所以我就来写个证明。
将 ( 看做 \(-1\),) 看做 \(1\),首先几个变量:

  • \(n\) 代表括号序列的长度。
  • \(a_i\) 代表前缀和。
  • \(b_i\) 代表后缀和。
  • \(mxa\) 代表 \(\max_{i=1}^n \left \{ a_i \right \}\)。
  • \(mxb\) 代表 \(\max_{i=1}^n \left \{\left | b_i \right | \right \}\)。

结论1: 一个括号序列是合法的等价于 \(∀i\in \left [1,n\right ]\),\(a_i\le0\) 且 \(∀i\in \left [1,n\right ]\),\(b_i\ge0\)。

证明1: 先证充分性,反证,若 \(∃i\in \left [1,n\right ]\),\(a_i>0\),那么就会出现 ) 使它前面没有更多的 ( 和它匹配。\(b\) 同理。再证必要性,满足上述条件就说明在任何位置都不会存在 ) 前面没有 ( 来和它匹配,( 后面没有 ) 和它匹配。

结论2: 若要使 \(a\) 不存在正数,那么 \(a\) 至少需要改变 $\left \lceil \dfrac{mxa}{2} \right \rceil $ 次。若要使 \(b\) 不存在负数,那么 \(b\) 至少需要改变 \(\left \lceil \dfrac{mxb}{2} \right \rceil\) 次。

证明2: 首先,对于 \(i\),若它是正数,那么将它变为非正数至少需要改变它及它之前中的 $\left \lceil \dfrac{a_i}{2} \right \rceil $ 个字符(一次改变使 \(1\) 变成 \(-1\),即使 \(a_i\) 减去 \(2\)),那么总花费不会小于 $\left \lceil \dfrac{mxa}{2} \right \rceil $,我们设 \(p\) 满足 \(p\in \left [1,n\right ]\) 且 \(a_p=mxa\),我们来考虑除了 \(p\) 之外的某个位置 \(j\) 的花费:

  1. \(j<p\):只需要将这 \(\left \lceil \dfrac{mxa}{2} \right \rceil\) 个操作从最左端开始往右依次使用,那么就一定能满足 \(j\)。
  2. \(j>p\):显然 \(p\) 满足了 \(j\) 也满足。

所以改变次数即为 $\left \lceil \dfrac{mxa}{2} \right \rceil \(。\)b$ 同理。

结论3: 若 \(p\) 满足 \(p\in \left [0,n\right ]\) 且 \(a_p=mxa\) 那么 \(\left | b_{i+1} \right | =mxb\)(将 \(a_0\) 与 \(b_{n+1}\) 看做 \(0\))。

证明3: 简单地推下式子:

\[b_{p+1}= n-a_p= n-mxa= n-\max _{i=0}^n \left \{ a_i \right \} = \min _{i=0}^{n} \left \{ n-a_i \right \} = \min _{i=1}^{n+1}\left \{ b_i \right \} = mxb \]

结论4: 将括号序列变成合法(即使 \(a\) 不存在正数,使 \(b\) 不存在负数)的最小操作次数为 \(\left \lceil \dfrac{mxa}{2} \right \rceil+\left \lceil \dfrac{mxb}{2} \right \rceil\) 。

证明4: 容易知道答案不会比 \(\left \lceil \dfrac{mxa}{2} \right \rceil+\left \lceil \dfrac{mxb}{2} \right \rceil\) 小,那么我们证明一定存在构造方案使得答案就是这个式子。记 \(p\) 满足 \(p\in \left [0,n\right ]\) 且 \(a_p=mxa\),考虑是否有可能在所有操作之后,\(a\) 或 \(b\) 不合法了。容易知道 \(mxa\) 和 \(mxb\) 奇偶性相同,分类讨论:

  1. 若 \(mxa\) 与 \(mxb\) 都是偶数,若我们先让 \(b\) 变成合法的,那么在操作后,\(b_{p+1}=0\) 并且 \(∀i\in \left [p+1,n+1\right ]\),\(b_i\ge0\),那么有 \(∀i\in \left [p+1,n+1\right ]\),\(b_{p+1}-b_i\le0\),再让 \(a\) 变为合法的,在 \(p\) 及之前的括号只会在让 \(a\) 合法的过程中改变,而在后面的位置,由于只会加上非正数,所以 \(a\) 仍然合法。
  2. 类似。

所以就证明出了答案就是 \(\left \lceil \dfrac{mxa}{2} \right \rceil+\left \lceil \dfrac{mxb}{2} \right \rceil\)。剩下的内容和其他题解就都一样了qwq。

code:

点击查看代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<cstdlib>
#include<ctime>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int N=1e5+10;

int ls[N],rs[N],sz[N],wei[N],lmx[N],rmx[N],lmi[N],rmi[N],val[N],sum[N],lz[N],lzs[N],lzv[N],tot,rt;
int New(int v)
{
	wei[++tot]=rand();sz[tot]=1;
	if(v==1)lmx[tot]=rmx[tot]=1; else lmi[tot]=rmi[tot]=-1;
	sum[tot]=val[tot]=v;
	return tot;
}
void pushup(int p)
{
	sz[p]=sz[ls[p]]+sz[rs[p]]+1,sum[p]=sum[ls[p]]+sum[rs[p]]+val[p];
	lmx[p]=max(lmx[ls[p]],sum[ls[p]]+val[p]+lmx[rs[p]]);
	lmi[p]=min(lmi[ls[p]],sum[ls[p]]+val[p]+lmi[rs[p]]);
	rmx[p]=max(rmx[rs[p]],sum[rs[p]]+val[p]+rmx[ls[p]]);
	rmi[p]=min(rmi[rs[p]],sum[rs[p]]+val[p]+rmi[ls[p]]);
}
void pushdown(int p)
{
	if(lz[p])
	{
		lz[ls[p]]=lz[rs[p]]=lz[p];
		lzs[ls[p]]=lzv[ls[p]]=lzs[rs[p]]=lzv[rs[p]]=0;
		val[ls[p]]=val[rs[p]]=lz[p];
		if(lz[p]==1)
		{
			sum[ls[p]]=sz[ls[p]],sum[rs[p]]=sz[rs[p]];
			lmx[ls[p]]=rmx[ls[p]]=sz[ls[p]];
			lmx[rs[p]]=rmx[rs[p]]=sz[rs[p]];
			lmi[ls[p]]=rmi[ls[p]]=lmi[rs[p]]=rmi[rs[p]]=0;
		}
		else
		{
			sum[ls[p]]=-sz[ls[p]],sum[rs[p]]=-sz[rs[p]];
			lmi[ls[p]]=rmi[ls[p]]=-sz[ls[p]];
			lmi[rs[p]]=rmi[rs[p]]=-sz[rs[p]];
			lmx[ls[p]]=rmx[ls[p]]=lmx[rs[p]]=rmx[rs[p]]=0;
		}
		lz[p]=0;
	}
	if(lzs[p])
	{
		lzs[ls[p]]^=1,lzs[rs[p]]^=1;
		swap(ls[ls[p]],rs[ls[p]]),swap(ls[rs[p]],rs[rs[p]]);
		swap(lmx[ls[p]],rmx[ls[p]]),swap(lmi[ls[p]],rmi[ls[p]]);
		swap(lmx[rs[p]],rmx[rs[p]]),swap(lmi[rs[p]],rmi[rs[p]]);
		lzs[p]=0;
	}
	if(lzv[p])
	{
		lzv[ls[p]]^=1,lzv[rs[p]]^=1;
		val[ls[p]]*=-1,val[rs[p]]*=-1;
		sum[ls[p]]*=-1,sum[rs[p]]*=-1;
		swap(lmx[ls[p]],lmi[ls[p]]),lmx[ls[p]]*=-1,lmi[ls[p]]*=-1;
		swap(rmx[ls[p]],rmi[ls[p]]),rmx[ls[p]]*=-1,rmi[ls[p]]*=-1;		
		swap(lmx[rs[p]],lmi[rs[p]]),lmx[rs[p]]*=-1,lmi[rs[p]]*=-1;
		swap(rmx[rs[p]],rmi[rs[p]]),rmx[rs[p]]*=-1,rmi[rs[p]]*=-1;
		lzv[p]=0;
	}
}
int merge(int x,int y)
{
	if(!x||!y)return x|y;
	if(wei[x]<wei[y]){pushdown(x),rs[x]=merge(rs[x],y),pushup(x);return x;}
	else {pushdown(y),ls[y]=merge(x,ls[y]),pushup(y);return y;}
}
void split(int p,int &x,int &y,int k)
{
	if(!p){x=y=0;return;}
	pushdown(p);
	if(sz[ls[p]]<k)x=p,split(rs[x],rs[x],y,k-sz[ls[p]]-1);
	else y=p,split(ls[y],x,ls[y],k);
	pushup(p);
}
void ins(int v){rt=merge(rt,New(v));}

int n,Q;
char str[N];
void spl(int l,int r,int &x,int &y,int &z){split(rt,y,z,r),split(y,x,y,l-1);}
void mer(int x,int y,int z){rt=merge(x,merge(y,z));}
int main()
{
	srand(time(0));
	cin>>n>>Q;
	scanf("%s",str+1);
	rep(i,1,n)ins(str[i]==')'?1:-1);
	while(Q--)
	{
		cin>>str[1];int l,r;
		if(str[1]=='R')
		{
			rep(i,1,6)cin>>str[1];
			cin>>l>>r>>str[1];
			int v=(str[1]==')'?1:-1);
			int x,y,z;
			
			spl(l,r,x,y,z);
			lz[y]=val[y]=v;
			lzs[y]=lzv[y]=0;
			if(v==1)sum[y]=lmx[y]=rmx[y]=sz[y],lmi[y]=rmi[y]=0;		
			else sum[y]=lmi[y]=rmi[y]=-sz[y],lmx[y]=rmx[y]=0;
			mer(x,y,z);
		}
		else if(str[1]=='S')
		{
			rep(i,1,3)cin>>str[1];
			cin>>l>>r;
			int x,y,z;
			spl(l,r,x,y,z);
			
			lzs[y]^=1;
			swap(ls[y],rs[y]),swap(lmx[y],rmx[y]),swap(lmi[y],rmi[y]);
			
			mer(x,y,z);
		}
		else if(str[1]=='I')
		{
			rep(i,1,5)cin>>str[1];
			cin>>l>>r;
			int x,y,z;
			spl(l,r,x,y,z);
			
			lz[y]*=-1,lzv[y]^=1;
			sum[y]*=-1,val[y]*=-1;
			swap(lmx[y],lmi[y]),lmx[y]*=-1,lmi[y]*=-1;
			swap(rmx[y],rmi[y]),rmx[y]*=-1,rmi[y]*=-1;					
			
			mer(x,y,z);
		}
		else
		{
			rep(i,1,4)cin>>str[1];
			cin>>l>>r;
			int x,y,z;
			spl(l,r,x,y,z);
			printf("%d\n",lmx[y]/2+(lmx[y]&1)+abs(rmi[y])/2+(abs(rmi[y])&1));
			mer(x,y,z);
		}
	}
	return 0;
}

标签:lmx,right,rs,题解,P3215,HNOI2011,ls,rmi,left
From: https://www.cnblogs.com/onlycre/p/17094191.html

相关文章

  • CF884D 题解
    题目传送门题目分析开始还真没看出来这题跟\(\text{P1090}\)合并果子的关系。其实只要逆向思考,把拆分看成效果一样的合并就可以了。而与合并果子不同的是,在这题当中......
  • abc285h题解
    考虑容斥,强制要求\(k\)个数为完全平方数,系数为\((-1)^k*C_n^k\)(因为我们要从\(n\)个数选出\(k\)个数作为完全平方数)。则在唯一分解\(p_1^{e_1}...p_n^{e_n}\)中,\(e_1...e_n......
  • "_OBJC_CLASS_$ [文件名1]referenced from in[文件名2]:ld: symbol(s) not found问题
    说实话开发一年多了,遇到了至少三次以上这种问题,很困惑,也很难搞觉得,其实很简单解决办法,在buildPhases中添加文件名1的.m文件即可了。"_OBJC_CLASS_$"PackageTourCustomAnnot......
  • 【题解】20230204解题报告
    解题报告20230204主要学习内容有:动态规划,字符串操作(在另外一篇文章里)T1:P5322[BJOI2019]排兵布阵首先题意是设定有n座城堡,s个玩家(不包括特殊玩家),此时每名玩家都有m......
  • lg9035题解
    考虑枚举\(a_{n-1}=l\),根据题意\(l\leqa_n\leqk+1-l\),这说明\(a_n\)有\(k+1-2l\)种取值。令\(b_i=a_i-a_{i-1}\),则\(b_1\geq1\),\(b_i\geq0(i>1)\),\(b_1+...+b_{n-1}=l......
  • 洛谷P9035 Pont des souvenirs 题解
    题面很简洁,这里不做多说。70pts做法首先考虑到\(a_{n-1}\)和\(a_n\)两项是整个数列\(a\)中的最大的两项,所以若\(a_{n-1}+a_n\)不超过\(k+1\),则数列中任意两项......
  • P2016题解
    P2016题解题目描述Bob要建立一个古城堡,城堡中的路形成一棵无根树。他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能瞭望到所有的路。注意,某个士兵在一个结点上时......
  • CF1666K Kingdom Partition 题解
    神仙网络流题。Description传送门Solution考虑最小割,将每个点\(u\)拆成\(L_u,R_u\)两个点。对于每一条原图中的边\((u,v,w)\),连双向边\((L_u,R_v,w),(L_v,R_u,w)......
  • 题解 ARC155D Avoid Coprime Game
    题解ARC155DAvoidCoprimeGame题意给定一个可重集\(S\),保证\(\gcd_{x\inS}(x)=1\),维护一个初始为\(0\)的整数\(G\),双方轮流操作,每次每人选择\(S\)中一个数......
  • circle 题解(思维+堆)
    题目有\(n\)个圆心在\(x\)轴上的不相交的圆(存在边界重合),求这些圆将平面分为几部分。保证\(1\leqn\leq3\times10^5\),\(-10^9\leqx_i,y_i\leq10^9\)。一个......