牛客网NOIP赛前集训营-提高组(第四场)B 区间(单调优化)
Posted ITAK
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客网NOIP赛前集训营-提高组(第四场)B 区间(单调优化)相关的知识,希望对你有一定的参考价值。
传送门
链接: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 ai作为最大公约数,以 i i i 为中心,分别往左和往右找对 a i = = 0 a_i==0 ai==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\\% 60% 的数据,因为数据全随机,所以可以过测试点5、6,那么我们来优化一下复杂度,我们发现这个是有单调性的,我们在枚举 a i a_i ai 的时候,不需要每个数都枚举,如果 a j % a i = = 0 a_j\\%a_i==0 aj%ai==0 的话,那么最大公约数为 a i a_i ai 的区间长度一定比最大公约数为 a j a_j aj 的区间长度长,所以我们向右枚举的时候,下标 i i i 不用每次都加1,直接跳到右侧第一个对 % a i ! = 0 \\%a_i!=0 %ai!=0 的下标的位置即可,这样的时间复杂度是 O ( n ) 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;
以上是关于牛客网NOIP赛前集训营-提高组(第四场)B 区间(单调优化)的主要内容,如果未能解决你的问题,请参考以下文章
牛客网NowCoder 2018年全国多校算法寒假训练营练习比赛(第四场)A.石油采集(dfs) B.道路建设(最小生成树prim) C.求交集(暴力) F.Call to your teacher