题解 CF1548B 【Integers Have Friends】
CF1548B Integers Have Friends
题目大意:
给定序列 \(a_1...a_n\) ,求最大区间 \([\,i\,,\,j\,]\) ,\(\exists\,m(m>1)\) 使得 \(a_i\equiv a_{i+1}\equiv a_{i+2}...\equiv a_j (\bmod m)\) 。
solution:
可知区间模 \(m\) 下余数相等,所以我们用个差分把余数消掉。对于差分数组,若有 \(m\mid d_k\,\,\,\,\{k|i\leq k\leq j,k\in\mathbb{N^+}\}\) ,即区间的 \(\gcd>1\) 则区间合法,可更新长度。显然区间长度是满足单调性的,可二分区间右端点,若区间合法,则二分的将右端点向右推。区间 \(\gcd\) 可用 \(\text{ST}\) 表或者线段树维护。
细节处理:
- \(1\leq a_i \leq 10^{18}\) 要开 \(\text{long long}\) 。
- 差分数组要取绝对值,负数的 \(\gcd\) 会出问题。
- 具体细节见代码。
代码
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;//不开 long long 见祖宗
const int N=2e5+5;
LL a[N];
LL f[N][20];
inline LL gcd(LL x,LL y){
if(!y) return x;
return gcd(y,x%y);
}
inline void ST(int n){//ST表预处理
int t=log(n)/log(2);
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]);
}
inline LL query(int l,int r){//ST表回答区间gcd
int p=log(r-l+1)/log(2);
return gcd(f[l][p],f[r-(1<<p)+1][p]);
}
int main(){
int T; scanf("%d",&T);
while(T--){
int n; scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
if(n==1){puts("1");continue;}//特判,
for(int i=1;i<n;i++)
f[i][0]=abs(a[i]-a[i+1]);//注意 abs
f[n][0]=1;
ST(n);
int ans=0;
for(int i=1;i<=n;i++){//枚举左端点
int l=i,r=n;
while(l<=r){//二分右边界
int mid=l+r>>1;
if(query(i,mid)>1)
ans=max(ans,mid-i+1),l=mid+1;//向右推
else r=mid-1;//向左推
}
}
printf("%d\n",ans+1);//差分数组变为原数组 ans+1
}
return 0;
}

浙公网安备 33010602011771号