题解 区间
Posted zsq259
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 区间相关的知识,希望对你有一定的参考价值。
题面
区间
问题描述
给出一个序列 a1, ..., an。
定义一个区间 [l,r] 是好的,当且仅当这个区间中存在一个 i,使得 ai 恰好等于 al, al+1, ...,
ar-1, ar 的最大公因数。
求最长的好的区间的长度。
输入格式
第一行 n,表示序列的长度;
第二行 n 个数 a1,a2,...,an。
输出格式
输出一行一个数,表示最长的好的区间的长度。
输入样例
5
4 6 9 3 6
输出样例
4
数据范围及说明
样例说明:选择区间 [2,5],i=4 即 ai 为 3 是满足好区间的要求。
对于测试点 1、2,n≤ 100;
对于测试点 3、4,n≤ 2,000;
对于测试点 5、6,n ≤ 200,000, ai≤ 100,且数据随机;
对于测试点 7、8、9,n ≤ 200,000;
对于测试点 10,没有特殊限制。
对于所有数据,n≤ 4x 106, 1≤ ai≤ 1018。
解析
(考场\(yy\)出的一个玄学做法(似乎是对的),这里仅说明不作证明)
考虑到一段好的区间,
它的\(gcd\)一定是区间内最小的数.
因此,对于每个\(i\),
我们分别求出它向左,向右的,连续的,都是\(a[i]\)的倍数的长度,
再对每个\(i\)统计答案.
然而如果一个一个找这样是\(O(n^2)\)的...
但是上面的方法还可以优化,
我们以向左为例,
假设现在到了\(i\),
设\(f[i]\)代表从\(i\)往左走第一个不是\(i\)的倍数的位置,
那么显然这一段的长度就是\(i-f[i]\).
但重点在下面:
先设\(f[i]=i-1\),
若\(a[i-1]\)%\(a[i]==0\),即\(a[i-1]\)为\(a[i]\)的倍数,
那么从\(f[i-1]+1\)到\(i-1\)就都是\(a[i]\)的倍数,
那我们就直接跳到\(f[i-1]\)再重复判断就行了.
code:
#include <iostream>
#include <cstdio>
#include <cstring>
#define int long long
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout)
using namespace std;
inline int read()
int sum=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0')if(ch=='-')f=-1;ch=getchar();
while(ch>='0'&&ch<='9')sum=sum*10+ch-'0';ch=getchar();
return f*sum;
const int N=4000005;
int n,a[N],f1[N],f2[N];
signed main()
// fre("block");
n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++)
int p=i-1;
while(p&&a[p]%a[i]==0) p=f1[p];
f1[i]=p;
for(int i=n;i>=1;i--)
int p=i+1;
while(p<=n&&a[p]%a[i]==0) p=f2[p];
f2[i]=p;
int ans=0;
for(int i=1;i<=n;i++) ans=max(ans,f2[i]-f1[i]-1);
printf("%lld\n",ans);
return 0;
以上是关于题解 区间的主要内容,如果未能解决你的问题,请参考以下文章