首页 > 其他分享 >题解 AcWing 1272. 与众不同

题解 AcWing 1272. 与众不同

时间:2023-10-16 09:34:08浏览次数:31  
标签:int 题解 1272 st 端点 ans 区间 now AcWing

题目描述

定义完美序列:若一个序列内没有重复的数,称这个数列为完美数列。

每次给定一个区间 \([l,r]\),求这个区间内最长的完美序列长度。

具体思路

设 \(len_i\) 表示从 \(i\) 出发往右的最长完美序列长度。

我们定义一个指针 \(st\),表示当前枚举的区间左端点,同时定义多一个指针 \(now\),表示当前枚举到了哪个点。

我们还要用一个 \(last\) 数组记录每个数上一次出现的位置。

image

如图所示,如果当前的数 \(a[now]\) 上一次出现的位置在 \(st\) 之后,说明 \(a[now]\) 是这段区间内第一个重复的,同时也说明 \(now\) 前面这段区间是没有重复的。

那么以 \(st \sim now-1\) 这段区间的点为起点的最长完美序列的右端点都是 \(now-1\)。

那我们就可以更新这一段的信息,同时将 \(st\) 指针指向 \(now\) 指针所处位置,并进行下一轮枚举。

这样我们就实现了 \(O(n)\) 处理出 \(len_i\) 的值。


接下来考虑区间查询。

image

如图所示,以 \(l \sim r\) 区间内的点为起点的最长完美序列的右端点都没有超过 \(r\),那么我们直接对 \(len_i\) 取最大值即可。

image

但是有可能有这种情况, 以 \(l \sim r\) 区间内的点为起点的最长完美序列的右端点超过 \(r\) 了,这个时候超过 \(r\) 的部分我们就不能要了。

那么我们就有暴力代码 \(1\):

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5,M=1e6+5;
int ed[N],last[2*M+5],a[N],len[N];
int main(){
	int n,m;scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		a[i]=a[i]+M;
	}
	int st=1,now=2;
	last[a[1]]=1;
	while(now<=n){
		if(last[a[now]]>=st){
			int pos=last[a[now]];
			for(int i=st;i<=pos;i++){
				ed[i]=now-1;
				len[i]=now-1-i+1;
				last[a[i]]=0;
			}
			st=pos+1;
		}
		last[a[now]]=now;
		now++;
	}
	for(int i=st;i<=n;i++){
		ed[i]=n;
		len[i]=n-i+1;
	}
	for(int i=1;i<=m;i++){
		int l,r;scanf("%d%d",&l,&r);
		l++,r++;
		int ans=0;
		for(int j=l;j<=r;j++){
			if(ed[j]>r){
				ans=max(ans,r-j+1);
			}
			else{
				ans=max(ans,len[j]);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

我们继续分析性质。

我们发现如果区间内有一个点 \(i\),以它为起点的最长完美序列的右端点超过了 \(r\),那么 \(i+1 \sim r\) 这一段区间内的点一定被包含在这段完美序列内,我们就不需要继续往后找了。

于是有暴力代码 \(2\):

#include<bits/stdc++.h>
#pragma GCC optimize("Ofast")
using namespace std;
const int N=2e5+5,M=1e6+5;
int ed[N],last[2*M+5],a[N],len[N];
int main(){
	int n,m;scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		a[i]=a[i]+M;
	}
	int st=1,now=2;
	last[a[1]]=1;
	while(now<=n){
		if(last[a[now]]>=st){
			int pos=last[a[now]];
			for(int i=st;i<=pos;i++){
				ed[i]=now-1;
				len[i]=now-1-i+1;
				last[a[i]]=0;
			}
			st=pos+1;
		}
		last[a[now]]=now;
		now++;
	}
	for(int i=st;i<=n;i++){
		ed[i]=n;
		len[i]=n-i+1;
	}
	for(int i=1;i<=m;i++){
		int l,r;scanf("%d%d",&l,&r);
		l++,r++;
		int ans=0;
		for(int j=l;j<=r;j++){
			if(ed[j]>r){
			    if(r-j+1>ans){
			        ans=r-j+1;
			        break;
			    }
			}
			else{
				ans=max(ans,len[j]);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

这个时候我们可以将询问离线操作,将右端点按升序排序。

我们定义一个 \(now\) 指针,是用来找到 \([l,r]\) 区间内第一个最长完美序列右端点大于等于 \(r\) 的点。

image

  • 对于 \(now \sim r\) 这段区间,即上图中的红色线段。贡献为 \(r-now+1\)。
  • 对于 \(l \sim now-1\) 这段区间,即上图中的黄色线段,由于它们最长完美序列右端点不超过 \(r\),我们就可以用第一份暴力代码的方式来求 \(l \sim now-1\) 这段区间 \(len_i\) 的最大值,我们可以用 st 表或者线段树来维护。

由于我们将区间右端点排好了序,因此每次的 \(now\) 指针只需要继承上一次的即可,就不用每次都重新枚举了。

时间复杂度:\(O(n \log n)\)。

Code

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5,M=1e6;
struct node{
	int l,r,id;
}q[N];
bool cmp(node n1,node n2){
	return n1.r<n2.r;
}
int ans[N];
int last[2*M+5],a[N],len[N];
int n,m,f[N][26],mylog[N];
void build(){
	for(int i=1;i<=n;i++){
		mylog[i]=log2(i);
	}
	for(int i=1;i<=n;i++){
		f[i][0]=len[i];
	}
	for(int j=1;j<=25;j++){
		for(int i=1;i+(1<<j)-1<=n;i++){
			f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
		}
	}
}
int query(int l,int r){
	int k=mylog[r-l+1];
	return max(f[l][k],f[r-(1<<k)+1][k]);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		a[i]=a[i]+M;
	}
	int st=1,now=2;
	last[a[1]]=1;
	while(now<=n){
		if(last[a[now]]>=st){
			int pos=last[a[now]];
			for(int i=st;i<=pos;i++){
				len[i]=now-1-i+1;
				last[a[i]]=0;
			}
			st=pos+1;
		}
		last[a[now]]=now;
		now++;
	}
	for(int i=st;i<=n;i++){
		len[i]=n-i+1;
	}
	build();
	for(int i=1;i<=m;i++){
		scanf("%d%d",&q[i].l,&q[i].r);
		q[i].l++,q[i].r++;
		q[i].id=i;
	}
	sort(q+1,q+m+1,cmp);
	now=1;
	for(int i=1;i<=m;i++){
		while(now+len[now]-1<q[i].r)now++;
		if(now<=q[i].l)ans[q[i].id]=q[i].r-q[i].l+1;
		else{
			ans[q[i].id]=max(q[i].r-now+1,query(q[i].l,now-1));
		}
	}
	for(int i=1;i<=m;i++){
		printf("%d\n",ans[i]);
	}
	return 0;
}

标签:int,题解,1272,st,端点,ans,区间,now,AcWing
From: https://www.cnblogs.com/reclusive2007/p/17766660.html

相关文章

  • ARC167D Good Permutation 题解
    题意给定一个长度为\(N\)的排列\((P_1,P_2,\cdots,P_N)\)。称一个排列\(P\)为“好排列”当且仅当对于所有\(1\leqx\leqN\),都能通过不停地使\(x\leftarrowP_x\)将\(x\)变成\(1\)。通过最小次数操作将\(P\)变成“好排列”,每次操作为交换\(P\)中的两个数\(P_i\)......
  • [CSP-S2019] 树的重心 题解
    [CSP-S2019]树的重心因为这道题令我十分兴奋,所以来写一下做完后的思考。这道题用到了树的重心的种种性质,在写解法的时候会一一点出其用处。首先,枚举每一条边,然后各自\(O(n)\)扫一次的\(O(n^2)\)做法是简单的。那么接下来,就会出现不同的解法了:优化\(O(n)\)求解的过程......
  • P9290 Luna likes Love 题解
    原题:[洛谷P9310]([P9310EGOI2021]LunalikesLove/卢娜爱磕cp-洛谷|计算机科学教育新生态(luogu.com.cn))题目大意给定一个长度为\(\large2n(n\leq10^5)\)的序列,序列中\(\large1\simn\)的每一个数都恰好出现两次。可进行两种操作:交换两个相邻的数的位置。......
  • 2023 香山杯 RE部分题解
      URL从哪里来 main函数断点下载这里 然后可以看到TempFileName,是out.exe.tmp,还包含路径,直接提取出来用IDA打开,一开始被url误导了,看到了下面的RC4加密去了,使用findcryt软件,看到一个base64加密,交叉引用 在这动态调试这个函数 里面的a1,有一串字符是base64密文 ,解......
  • 【ZROJ2730】简单题 可持久化分块题解
    Description给定一棵\(n\)个节点的树,每次询问编号为\([l,r]\)的点中有多少个是祖先关系。\(n,q\le10^5\)。Solution直接做的话树上的祖先关系不好统计,那么转化到\(\texttt{dfs}\)序上,如果\(u\)是\(v\)的祖先那么\(dfn_u\ledfn_v<dfn_u+siz_u\)。把\([d......
  • AtCoder Beginner Contest 324 DF题题解
    比赛链接D-SquarePermutation其实比较简单,但是比赛时候脑子不转了,竟然在尝试枚举全排列,然后算了一下复杂度直接不会做了。正解应该是枚举完全平方数,底数枚举到\(sqrt(10^{14})\)即可,因为n最大为13。然后统计一下这个完全平方数各个数字出现了多少个,和读入的比较一下是......
  • Acwing.第125场周赛
    比赛链接数量给定一个正整数n,请你计算[1,n]范围内一共有多少个正整数满足能被2整除,但不能被3整除。输入格式一个正整数n。输出格式一个整数,表示满足条件的整数的数量。数据范围前3个测试点满足1≤n≤100。所有测试点满足1≤n≤10000。思路:一个比较简单的模拟......
  • 网络规划设计师真题解析--HDLC(帧类型)
    HDLC协议通信过程如下图所示,其中属于U帧的是(13)。(2021)A.仅SABME          B.SABME和UA C.SABME、UA和REJ,1    D.SABME、UA和I,0,0答案:B解析:HDLC帧类型如图:bit01234567I帧0N(S)发送帧序号3bit,取值23(0-7)P/FN(R)下一个预期要接收帧的序号3bit,取值23(0-7)S帧10S......
  • ABC324题解
    A/B赛时没打。C暴力判断是相等s[i]==t还是替换了一个字符,或者是添加/删除了一个字符。最后两个判断只需要交换一下\(s\)和\(t\)的顺序就可以共用一个函数了。D注意到\(N\le13\),所以平方数不会超过\(v=10^{13}\),很容易想到暴力枚举\(\sqrtv\)以内的数,判断是否......
  • P9517 drink 题解
    P9517drink题解Part1提示题目传送门欢迎大家指出错误并私信这个蒟蒻欢迎大家在下方评论区写出自己的疑问(记得@这个蒟蒻)Part2更新日志2023-08-1218:06文章完成2023-08-1415:53文章通过审核Part3解析这道题考场上用的查找做的。先用一个结构体分别表示......