区间 题解

题意简述

求长度为 n 的序列 a 的最长连续子序列 [l,r],满足 i[l,r],gcd(al,,ar)=ai

1n4×1061ai1018

题目分析

根据 gcd(a,b)=a 等价于 bmoda=0,这个区间的限制等价于 j[l,r],ajmodai=0。进而我们发现,可以在 ai 处统计答案,将问题转化为两部分。即,我们需要求出 li,表示最小的位置,满足 j[li,i],ajmodai=0ri 同理。

我们直接扫是 Θ(n2) 的,看看有没有地方重复计算了。显然是有的,比如有个 k<j,并且 akmodaj=0,我们扫过 ajmodai=0 后,就不用去扫 ak 了。于是,我们想到,可以直接从 lj1 继续扫下去。这样的时间复杂度如何保证呢?考虑这个算法的本质,就是维护了一个栈,栈中相邻的都不能整除。当我们新加入一个 ai 时,从 lj1 继续扫下去,可以看做是弹栈,因为之后就不会访问到 j 了。所以,这样的时间复杂度是线性 Θ(n) 的。

代码

#include <cstdio>
const int MAX = 1 << 28;
char buf[MAX], *p = buf;
#ifdef XuYueming
# define fread(_, __, ___, ____)
#else
# define getchar() *p++
#endif
#define isdigit(x) ('0' <= x && x <= '9')
#define __yzh__(x) for (; x isdigit(ch); ch = getchar())
template <typename T>
inline void read(T &x) {
x = 0; char ch = getchar(); __yzh__(!);
__yzh__( ) x = (x << 3) + (x << 1) + (ch ^ 48);
}
const int N = 4000010;
using lint = long long;
int n, ans, stack[N], *top = stack, L[N], *Li = L;
lint val[N];
signed main() {
#ifndef XuYueming
freopen("interval.in", "r", stdin);
freopen("interval.out", "w", stdout);
#endif
fread(buf, 1, MAX, stdin);
read(n);
register int i;
for (i = 1; i <= n; ++i) {
read(val[i]);
while (top != stack && val[*top] % val[i] == 0) --top;
*++Li = *top + 1, *++top = i;
}
*(top = stack) = n + 1;
for (i = n; i; --i) {
while (top != stack && val[*top] % val[i] == 0) --top;
if (*top - *Li > ans)
ans = *top - *Li;
*++top = i, --Li;
}
printf("%d", ans);
return 0;
}
posted @   XuYueming  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示