题目概述 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]); } } 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 ; }