ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【考试总结】2022-07-13

2022-07-13 16:00:53  阅读:136  来源: 互联网

标签:13 07 int mxtop cros pos 2022 区间 Mx


计蒜客题

从左到右枚举区间右端点并求出来有几个左端点满足条件

单调栈维护当前遍历到的 \(i\) 为右端点的区间的最大/最小值,每个栈中元素作为最值的区间在它加入栈之后不会延长,那么计算出来这段区间里面有哪些满足条件。

入栈的时候求出,弹栈的时候删掉即可

Code Display
const int N=1e6+10;
int n,x,a[N],ans;
int mnstk[N],mntop,mnl[N];
int mxstk[N],mxtop,mxl[N];
map<int,int> Mn,Mx;
vector<pair<int,int> > mnc[N],mxc[N];
signed main(){
	freopen("garlic.in","r",stdin); freopen("garlic.out","w",stdout);
	n=read(); x=read();
	int val=0;
	for(int i=1;i<=n;++i){
		a[i]=read();
		while(mntop&&a[i]<=a[mnstk[mntop]]){
			int pos=mnstk[mntop];
			Mn.erase(a[pos]);
			for(auto t:mnc[pos]){
				if(Mx[a[t.fir]]!=t.fir) continue;
				val-=t.sec;
			}
			--mntop;
		}
		while(mxtop&&a[i]>=a[mxstk[mxtop]]){
			int pos=mxstk[mxtop];
			Mx.erase(a[pos]);
			for(auto t:mxc[pos]){
				if(Mn[a[t.fir]]!=t.fir) continue;
				val-=t.sec;
			}
			--mxtop;
		}
		//insert stack
		mnstk[++mntop]=i; 
		Mn[a[i]]=i; 
		mnl[i]=1+mnstk[mntop-1];
		mxstk[++mxtop]=i; 
		Mx[a[i]]=i; 
		mxl[i]=1+mxstk[mxtop-1];
		if(Mn.count(x-a[i])){
			int pos=Mn[x-a[i]];
			int cros=max(0ll,1+min(i,pos)-max(mnl[pos],mxl[i]));
			if(cros){
				mnc[pos].emplace_back(i,cros);
				mxc[i].emplace_back(pos,cros);
				val+=cros;
			}
		}
		if(Mx.count(x-a[i])&&x!=a[i]*2){
			int pos=Mx[x-a[i]];
			int cros=max(0ll,1+min(i,pos)-max(mxl[pos],mnl[i]));
			if(cros){
				mxc[pos].emplace_back(i,cros);
				mnc[i].emplace_back(pos,cros);
				val+=cros;
			}
		}
		ans+=val;
	}
	print(ans);
	return 0;
}

奶牛题

从 \(1\sim m\) 枚举能操作最高位,此时如果有路径上的一个点操作了最高位那么以后就不能操作最高位了,变成了两个子问题

设 \(f_{h,i,j}\) 表示操作的最高位不超过第 \(h\) 位,不钦定第一步最后一步按在哪里的情况下从 \(i\) 到 \(j\) 的方案数。

如果没有操作最高位的元素就使用 \(f_{h-1,i,j}\) 转移,否则枚举最高位操作处 \(k\) 以及路径上的前驱后继 \(p,n\) 用 \(f_{h-1,i,p}\times f_{h-1,n,j}\) 转移

将所有的可行 \(p,n\) 求和再乘积复杂度 \(\Theta(n^3)\)

这个转移的用处在于询问的时候第一步最后一步被钦定了,那么将 \(n\) 个点变成 \(n+Q\) 个节点。此时 \(f_{h,i,j}\) 在 \(i,j\le n\) 时含义不变,在 \(i>n\) 时表示第一步被钦定选 \(bs\),\(j>n\) 时也类似。

在 \(h=bs\) 的时候开始转移 \(dp_{h,i+n,*}\),\(h=bt\) 时开始转移 \(dp_{h,*,i+n}\) 即可

Code Display
const int N=70;
int n,m,Q;
int dp[N][N<<1][N<<1],lef[N<<1],rig[N<<1];
char str[N][N];
bool G[N][N];
int s[N],t[N],bs[N],bt[N];
signed main(){
	freopen("cow.in","r",stdin);
	freopen("cow.out","w",stdout);
	n=read(); m=read(); Q=read();
	for(int i=1;i<=n;++i){
		scanf("%s",str[i]+1);
		for(int j=1;j<=n;++j) G[i][j]=str[i][j]-'0';
	}
	for(int i=1;i<=Q;++i){
		bs[i]=read(); s[i]=read();
		bt[i]=read(); t[i]=read();
	}
	for(int h=1;h<=m;++h){
		for(int i=1;i<=n+Q;++i){
			for(int j=1;j<=n+Q;++j) dp[h][i][j]=dp[h-1][i][j];
		}
		for(int k=1;k<=n;++k){
			for(int i=1;i<=n;++i) lef[i]=rig[i]=0;
			lef[k]=rig[k]=1;
			for(int i=1;i<=Q;++i){
				lef[i+n]=bs[i]==h&&s[i]==k;
				rig[i+n]=bt[i]==h&&t[i]==k;
			}
			for(int i=1;i<=n+Q;++i){
				for(int j=1;j<=n;++j){
					if(G[j][k]) ckadd(lef[i],dp[h-1][i][j]);
				}
			}
			for(int i=1;i<=n;++i){
				for(int j=1;j<=n+Q;++j){
					if(G[k][i]) ckadd(rig[j],dp[h-1][i][j]);
				}
			}
			for(int i=1;i<=n+Q;++i){
				for(int j=1;j<=n+Q;++j){
					ckadd(dp[h][i][j],mul(lef[i],rig[j]));
				}
			}
		}
	}
	for(int i=1;i<=Q;++i) print(dp[m][i+n][i+n]);
	return 0;
}

青蛙题

注意到一个区间的子区间颜色数最大不会超过其本身的颜色数,那么在扫描线过程中维护每个左端点到当前右端点的最大颜色数以及达到该颜色的最短区间

右端点右移到 \(r+1\) 时将最后一次该颜色出现位置到 \(r+1\) 的颜色数加一并更改最短区间长度为 \(r-i+1\)

把暴力的过程用线段树维护,每个叶子维护二元组 \((num,len)\) 表示颜色数和最短区间,区间维护 \(num\) 最大的二元组中 \(len\) 最小的一个

此时并不能支持区间修改得到新的 \(len\),但是发现这就是找到最靠右的 \(num\) 最大的,那么再维护一下位置即可

Code Display
const int N=2e6+10;
int n,Q,a[N],ans[N],lst[N];
vector<pair<int,int> >qu[N];
struct Segment_Tree{
	pair<int,int> Mx[N<<2];
	int Rmx[N<<2],delt[N<<2],R[N<<2];
	inline void push_tag(int p,int d,int r){
		Mx[p]={Mx[p].fir+d,r-Rmx[p]+1};
		R[p]=r; delt[p]+=d;
	}
	inline void push_down(int p){
		if(delt[p]){
			push_tag(p<<1,delt[p],R[p]);
			push_tag(p<<1|1,delt[p],R[p]);
			delt[p]=0; 
			R[p]=0;
		}
		return ;
	}
	inline void push_up(int p){
		if(Mx[p<<1].fir>Mx[p<<1|1].fir){
			Rmx[p]=Rmx[p<<1];
			Mx[p]=Mx[p<<1];
		}else{
			Mx[p]=Mx[p<<1|1];
			if(Mx[p].fir==Mx[p<<1].fir) ckmin(Mx[p].sec,Mx[p<<1].sec);
			Rmx[p]=Rmx[p<<1|1];
		}
	}
	inline void insert(int st,int ed,int p=1,int l=1,int r=n){
		if(st<=l&&r<=ed){
			push_tag(p,1,ed);
			return ;
		}
		int mid=(l+r)>>1; push_down(p);
		if(st<=mid) insert(st,ed,p<<1,l,mid);
		if(ed>mid) insert(st,ed,p<<1|1,mid+1,r);
		return push_up(p);
	}
	inline pair<int,int> query(int st,int ed,int p=1,int l=1,int r=n){
		if(st<=l&&r<=ed) return Mx[p];
		int mid=(l+r)>>1; push_down(p);
		if(ed<=mid) return query(st,ed,p<<1,l,mid);
		if(st>mid) return query(st,ed,p<<1|1,mid+1,r);
		pair<int,int> lres=query(st,ed,p<<1,l,mid);
		pair<int,int> rres=query(st,ed,p<<1|1,mid+1,r);
		if(lres.fir^rres.fir) return lres.fir>rres.fir?lres:rres;
		return {lres.fir,min(lres.sec,rres.sec)};
	}
	inline void build(int p,int l,int r){
		Rmx[p]=r; Mx[p].sec=1;
		if(l==r) return ;
		int mid=(l+r)>>1;
		build(p<<1,l,mid); build(p<<1|1,mid+1,r);
	}
}T;
int main(){
	freopen("frog.in","r",stdin);
	freopen("frog.out","w",stdout);
	n=read();
	rep(i,1,n) a[i]=read();
	Q=read();
	for(int i=1;i<=Q;++i){
		int l=read(),r=read();
		qu[r].emplace_back(l,i);
	}
	T.build(1,1,n);
	for(int i=1;i<=n;++i){
		T.insert(lst[a[i]]+1,i);
		for(auto q:qu[i]) ans[q.sec]=T.query(q.fir,i).sec;
		lst[a[i]]=i;
	}
	for(int i=1;i<=Q;++i) print(ans[i]);
	return 0;
}

标签:13,07,int,mxtop,cros,pos,2022,区间,Mx
来源: https://www.cnblogs.com/yspm/p/TestReview20220713.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有