Codeforces 1549D - Integers Have Friends

Codeforces 1549D - Integers Have Friends

八月 02, 2021

题目概述

Define a subarray $a_i,a_{i+1},…,a_j$​​​ to be a friend group if and only if there exists an integer $m≥2$​ such that $a_i\; mod\;m=a_{i+1}\;mod\;m=…=a_j\;mod\;m$​,

Your friend Gregor wants to know the size of the largest friend group in $a$.

数据范围

分析与解

这个题没做出来真是太可惜了!其实就是求一个序列最长的GCD区间,基本的想法都想到了,却栽在这个数据结构的处理上。

核心问题:双指针。

区间GCD和区间max,区间min都是符合叠加原则的,因此它的单调性就在于如果我的区间范围越大,那么区间GCD趋向于更小。因此我们只需要有ST表来$O(logn)$预处理,$O(1)$询问来验证一个区间的GCD,然后固定右端点,不断地跳左端点来更新最大区间就行了!

复杂度 $O(Nlog1e18logn)$

注意ST表怎么来$O(1)$查询的!

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define MAXN 200100
LL mread() {
LL ret=0,f=1;
char c=getchar();
while(c<'0' || c>'9') {
if(c=='-')f=-1;
c=getchar();
}
do {
ret=ret*10+c-'0';
c=getchar();
} while('0'<=c && c<='9');
return ret*f;
}
LL gcd(LL a,LL b) {
if(b==0)return a;
return gcd(b,a%b);
}
LL a[MAXN],d[MAXN];
int n;
namespace ST {
LL st[MAXN][22];
void build() {
for(int i=1; i<=n-1; i++)st[i][0]=d[i];
for(int j=1; j<=22; j++)
for(int i=1; i+(1<<j)-1<=n-1; i++)
st[i][j]=gcd(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
LL query(int l,int r) {
LL ret=-1;
int h=floor(log2(r-l+1));
return gcd(st[l][h],st[r-(1<<h)+1][h]);//ST表的运用最大覆盖即可
}
}

int main() {
int kase;
int ans,j;
kase=mread();
while(kase--) {
n=mread();
for(int i=1; i<=n; i++)a[i]=mread();
for(int i=1; i<n; i++)d[i]=abs(a[i+1]-a[i]);
ST::build();
j=1,ans=1;//初始化!
for(int i=1; i<=n-1; i++) {
while(j<=i && ST::query(j,i) == 1)j++;
ans=max(ans,i-j+2);
}
printf("%d\n",ans);
}
return 0;
}