题解:P10264 [GESP202403 八级] 接竹竿
考虑暴力。
思路
预处理出每一个数的后继(即下一个出现的位置)
对于每一个询问区间枚举,如果发现枚举的数的后继在区间内,那么就跳过这个区间。
可以这么理解:因为当你在后面枚举到它的后继的时候,你就要把它和它的后继之间的所有数全部拿走。拿走的部分不应统计出答案。
例如 1 1 6 4 5 1 4 1
,
- 我们读入
1
。序列为1
。 - 我们又读入
1
,序列为1 1
,需要消除,消除后序列为空。 - 依次读入
6 4 5 1
,序列为4 5 1
。 - 读入
4
,序列为4 5 1 4
,消除后变为6
。 - 读入
1
,无法再进行匹配,序列变为1 6
。
可以发现,在从前向后枚举的过程中,枚举到的数和它后继之间的数都要被消除掉(例如 4 5 1 4
)。因此该算法正确。
核心代码如下:
while(q--) {
l=read(),r=read();
int ans=0;
for(int i=l; i<=r; i++) {
if(nxt[i]<=r) {// nxt 数组即预处理出的后继
i=nxt[i];// 跳过这个区间
// 因为执行完 i=nxt[i] 操作后会进行 i++ 操作,所以下一次进入循环是 nxt[i]+1 的值。
} else ans++;
}
printf("%d\n",ans);
}
复杂度分析
因为
即均摊下来复杂度最大可以达到
完整代码如下。
#include<bits/stdc++.h>
using namespace std;
int a[15005],pre[15005],nxt[15005],last[15];
int n,q,l,r,T;
inline int read() {
int x=0,y=1;
char c=getchar();
while(c>'9'||c<'0') {
if(c=='-')y=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*y;
}
int main() {
T=read();
while(T--) {
n=read();
for(int i=1; i<=n; i++)a[i]=read();
memset(last,0,sizeof(last));
for(int i=1; i<=n; i++) {
pre[i]=last[a[i]];
last[a[i]]=i;
}
for(int i=1; i<=13; i++)last[i]=n+1;
for(int i=n; i>=1; i--) {
nxt[i]=last[a[i]];
last[a[i]]=i;
}
// for(int i=1;i<=n;i++)cout<<nxt[i]<<' ';
q=read();
while(q--) {
l=read(),r=read();
int ans=0;
for(int i=l; i<=r; i++) {
if(nxt[i]<=r) {
i=nxt[i];
} else ans++;
}
printf("%d\n",ans);
}
}
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】