牛客网NOIP赛前集训营-提高组(第四场)B 区间(单调优化)

版权声明:编写不易,转载请注明出处,谢谢。 https://blog.csdn.net/qingshui23/article/details/82963994

传送门
链接: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。

解题思路:

根据题意,那么我们枚举一个 a i a_i 作为最大公约数,以 i i 为中心,分别往左和往右找对 a i = = 0 a_i==0 的数字,然后我们记录一下长度,代码如下:

#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;
}

但是这个复杂度太高,只能过 60 % 60\% 的数据,因为数据全随机,所以可以过测试点5、6,那么我们来优化一下复杂度,我们发现这个是有单调性的,我们在枚举 a i a_i 的时候,不需要每个数都枚举,如果 a j % a i = = 0 a_j\%a_i==0 的话,那么最大公约数为 a i a_i 的区间长度一定比最大公约数为 a j a_j 的区间长度长,所以我们向右枚举的时候,下标 i i 不用每次都加1,直接跳到右侧第一个对 % a i ! = 0 \%a_i!=0 的下标的位置即可,这样的时间复杂度是 O ( n ) O(n) 的。

代码如下:

#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;
}

猜你喜欢

转载自blog.csdn.net/qingshui23/article/details/82963994