题解 区间

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;

以上是关于题解 区间的主要内容,如果未能解决你的问题,请参考以下文章

NOI2016区间 题解

题解序列终结者

P4198 楼房重建 题解

SDOI2016 征途 题解

LOJ132. 树状数组 3 :区间修改,区间查询 题解

9.5题解