Integers Have Friends 思维、双指针、st表
大意:给定一个长度为 n 的序列,若存在一段连续的子序列 [l,r] 满足
a l m o d m = a l + 1 m o d m = . . . . . . = a r m o d m a_l \mod m = a_{l+1} \mod m = ...... =a_r \mod m almodm=al+1modm=......=armodm (m>=2)则称该子序列为 友好子序列。
求满足条件的最长友好子序列长度。
思路:对于 a%m=b%m 通过移项,其实也就是 (a-b)%m=0。原问题中的友好子序列就转化成了
子序列中的任意两个数的差值都是 m 的倍数。对于三个数 a, b, c 若 (a-b)%m=0,(b-c)%m=0
那么必有 (a-c)%m=0(上面两式相加就行了)。所以只需要相邻两个数的差值是 m 的倍数就行了。m>=2 ,进一步将问题转化,[l,r] 是友好子序列,其实也就是令 b i = a i − a i − 1 b_i=a_i-a_{i-1} bi=ai−ai−1,b 序列中的 [ l + 1 , r ] [l+1,r] [l+1,r] gcd>1。根据gcd的性质,若区间 [l,r]的gcd=1,那么[l,x] (x>r) 的gcd 也始终是1,所以可以用双指针来写。需要用st 表快速查询区间 gcd 。
代码如下:
#include <bits/stdc++.h>
#define int long long
#define rep(i,bbb,eee) for(int i=bbb;i<=eee;i++)
#define frep(i,bbb,eee) for(int i=bbb;i>=eee;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define cout(xxx) cout<<fixed<<setprecision(xxx)
#define inf 0x3f3f3f3f
#define pb push_back
#define AC signed
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=200010,M=998244353;
int qmi(int a,int b)
{
int res=1;
while(b)
{
if(b&1)res=res*a%M;
a=a*a%M;
b>>=1;
}
return res%M;
}
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
inline void print(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
//____________________________________________//
int n,m,f[N][20],a[N],st[N];
void init()
{
for(int j=0;(1<<j)<=n;j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
if(!j)f[i][j]=abs(a[i]-a[i-1]);
else f[i][j]=__gcd(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
}
}
int query(int l,int r)
{
int k=r-l+1;
k=st[k];
return __gcd(f[l][k],f[r-(1<<k)+1][k]);
}
void solve()
{
cin>>n;
rep(i,1,n)cin>>a[i];
init();
int ans=1;
for(int i=2,j=2;i<=n;i++)
{
while(j<i&&query(j,i)==1)j++;
if(query(j,i)>1)ans=max(ans,i-j+2);
}
cout<<ans<<"\n";
}
AC main()
{
ios::sync_with_stdio(false);cin.tie(0);
for(int j=0;j<=18;j++)
{
int t=1<<j;
if(t>=N)break;
st[t]=j;
}
for(int i=1;i<N;i++)if(!st[i])st[i]=st[i-1];
int _=1;
cin>>_;
while(_--)solve();
return 0;
}