传送门
链接:https://www.nowcoder.com/acm/contest/175/B
来源:牛客网
题目描述
给出一个序列 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 10^6, 1≤ ai≤ 10^18。
解题思路:
根据题意,那么我们枚举一个 作为最大公约数,以 为中心,分别往左和往右找对 的数字,然后我们记录一下长度,代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 4e6+5;
LL a[MAXN];
int main()
{
int n; cin>>n;
for(int i=0; i<n; i++) cin>>a[i];
int ans = 1;
for(int i=0; i<n; i++)
{
int l = i, r = i;
for(int j=i+1; j<n; j++)
{
if(a[j]%a[i] == 0) r = j;
else break;
}
for(int j=i-1; j>=0; j--)
{
if(a[j]%a[i] == 0) l = j;
else break;
}
ans = max(ans, r-l+1);
}
cout<<ans<<endl;
return 0;
}
但是这个复杂度太高,只能过 的数据,因为数据全随机,所以可以过测试点5、6,那么我们来优化一下复杂度,我们发现这个是有单调性的,我们在枚举 的时候,不需要每个数都枚举,如果 的话,那么最大公约数为 的区间长度一定比最大公约数为 的区间长度长,所以我们向右枚举的时候,下标 不用每次都加1,直接跳到右侧第一个对 的下标的位置即可,这样的时间复杂度是 的。
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 4e6+5;
LL a[MAXN];
int main()
{
ios::sync_with_stdio(false); cout.tie(0); cin.tie(0);
int n; cin>>n;
for(int i=0; i<n; i++) cin>>a[i];
int ans = 1;
for(int i=0; i<n; )
{
int l = i, r = i;
for(int j=i+1; j<n; j++)
{
if(a[j]%a[i] == 0) r = j;
else break;
}
for(int j=i-1; j>=0; j--)
{
if(a[j]%a[i] == 0) l = j;
else break;
}
i = r+1;
ans = max(ans, r-l+1);
}
cout<<ans<<endl;
return 0;
}