题目描述
给出一个序列 a1, …, an。 定义一个区间 [l,r] 是好的,当且仅当这个区间中存在一个 i,使得 ai 恰好等于 al, al+1, …, ar-1, ar 的最大公因数。 求最长的好的区间的长度。
输入描述:
第一行 n,表示序列的长度;第二行 n 个数 a1,a2,…,an。
输出描述:
输出一行一个数,表示最长的好的区间的长度。
示例1
输入
5
4 6 9 3 6
输出
4
说明
选择区间 [2,5],i=4。
备注:
对于测试点 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 1 0 6 10^6 106, 1≤ ai≤ 1 0 1 8 10^18 1018。
90分思路:
第一次90分
• 注意到:如果 ? 的区间扩展到了 ?,那么 ? 的区间一定是 ? 的区间的子区间(因为 ? 是 ? 的一个倍
数),从而不可能更新答案
• 我们可以考虑按一个顺序枚举 ?,每次只要一个点被区间经过,就可以不用扩展它的区间
• 按 ?? 从小到大的顺序扩展 ?,这样每一个数最多被扩展过两次(从左和从右分别一次)
• 时间复杂度为排序复杂度 O(nlogn)O(nlogn)
以上是官方给出的部分题解,也就是复杂度较高的题解。
照着思路写了一遍得到了90分。
这里需要注意一个问题,就是这里j被扩展到是有方向的,也就是说如果单纯的将被扩展之后的位置打上标记的话是错误的(虽然仍然能够得到90分,数据水。)
如下面的数据:
5
4 72 36 9 18
我们会先从4开始扩展,那么如果这个时候就给72 和 36打上标记的话,我们再从9扩展的时候就无法扩展到72和36。所以原本最长的答案4就会变成3。
观察怎么解决这个问题,我们考虑如果9在4右边在72和36的左边,那么就会出现4的区间会包括9的区间,那么把vis带上方向判断就可以了。
vis[i][0]vis[i][0]表示i这个位置的点有没有被其左边的点更新过。
vis[i][1]vis[i][1]表示这个位置的点有没有被其右边的点更新过。
90分代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
const int wx=4000017;
inline char get_char(){
static char buf[1000001],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
#define short long long
inline short read()