题解 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;
}

End

posted @ 2021-08-07 19:14  Mr_think  阅读(154)  评论(0)    收藏  举报