本题暴力循环是使不得的,本人亲测。
首先分析得到,n个数进行gcd操作的结果就是最终的相同的数(自行举几个例子就可以得出这个结论)。
我们注意到转换的步骤有几次,i就和他后面几个数进行gcd操作,而操作次数一定是单调的,所以可以采用二分来优化。
二分出操作次数后,就进行区间查询的操作,在[i,i+mid]区间中进行查询,高效的静态区间查询的数据结构可以采用st表来处理,每次查询的复杂度是o(1),非常优秀。
查询每个区间是否与最终相同的数相同,如果不同,说明区间太小,无法gcd到相同的数,就l=mid+1。
#include<bits/stdc++.h>
using namespace std;
const int M=2e5+5;
int a[M<<1];
int st[M<<1][21];
int n;
int g;
int gcd(int a,int b){
int r=a%b;
while(r){
a=b; b=r; r=a%b;
}
return b;
}
int getGcd(int l,int r){
int k=log2(r-l+1);
return gcd(st[l][k],st[r-(1<<k)+1][k]);
}
bool check(int x){
for(int i=1;i<=n;i++){
if(g!=getGcd(i,i+x)) return 0;
}
return 1;
}
int main(){
int t; cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i+n]=a[i];
if(i==1) g=a[i];
else g=gcd(g,a[i]);
}
// cout<<"dao"<<endl;
for(int i=1;i<=2*n;i++) st[i][0]=a[i];
for(int j=1;j<=20;j++){
for(int i=1;i<=2*n;i++){
if(i+(1<<j)-1<=2*n)
st[i][j]=gcd(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
}
int l=0; int r=n-1;
// cout<<"dao"<<endl;
while(l<r){
// cout<<"1"<<endl;
int mid=(l+r)>>1;
if(check(mid)){
r=mid;
}
else{
l=mid+1;
}
}
cout<<l<<'\n';
}
return 0;
}