Integers Have Friends cf 1549D 【ST表+单调队列】
CodeForces 1549D -> Click Here
题意
数组\(a_1,a_2,a_3,...,a_n\)中定义一个 subarray \(a_i,a_{i+1},a_{i+2},...,a_{j}\) 为friends group 当且仅当存在一个\(m\)使得\(a_i \%m=a_{i+1}\%m=...=a_j\%m\) (\(x\%y\)表示x除y的余数),询问长度最大的 friends group
思路
因为对\(m\)取余数所以若存在一个\(m\)使\(a\%m=b\%m=c\%m\)则\(a\),\(b\),\(c\)之间差值的最大公约数\(\geq2\)
所以建立一个数组\(\bf{B}\),存放\(a\)中相邻数的差值使\(b_i=a_{i+1}-a_i\)
用ST表存B中\(l\)到\(r\)的最大公约数,再用单调队列遍历一遍即可
具体细节见code ↓
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll A[200005],n;//A存输入的a数组
ll B[200005];//B存A中相邻数的差
ll f[200005][22];//ST表
void ST_prework(){// ST表预处理B中的gcd(最大公约数)
int t=log(n)/log(2)+1;
for(int i=1;i<=n;i++) f[i][0]=B[i];
for(int j=1;j<t;j++)
for(int i=1;i<=n-(1<<j)+1;i++)
f[i][j]=__gcd(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
ll query(ll l,ll r){//ST表查找B中l到r的gcd
int k=log(r-l+1)/log(2);
return __gcd(f[l][k],f[r-(1<<k)+1][k]);
}
void solve(){
int ans=0;
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&A[i]);
for(int i=1;i<=n;i++) B[i]=abs(A[i+1]-A[i]);//做差
n--;//差数组的大小为n-1
ST_prework();//预处理
for(int i=1,j=2;i<=n;i++){//起始位置l为i=1,r为j=2,开始单调队列
if(i==j) j++;//右端点恒大于左端点
while((query(i,j)>=2&&j<=n)) j++;//如果l到r的gcd大于二则 右端点向右移动
if(j-i>=1&&query(i,j-1)>=2) ans=max(j-i,ans);//若l到r不符合gcd>=2则更新答案
}
cout<<ans+1<<endl;//ans存的是差值个数 输出时应ans+1输出
}
int main(){
int T;scanf("%d",&T);
while(T--) solve();
return 0;
}
小节
最开始就观察到了做差取 gcd ,但后面直接\(O(n)\)扫一遍看当前差值是否于前一位的差值的gcd相同
最后样例
1
8
1 3 5 11 17 20 23 3 2
成功将我卡飞

浙公网安备 33010602011771号