ST
- (利用二进制进行跳(优化时间复杂度))(预处理 nlogn) 查询 O(1);
- 处理 RMQ和GCD问题(重复计算部分无所谓)
arr[i][j] 代表 i —— i+(1<<j)-1 这一区间的值, 区间长度为 1<<j.
void init() { for(ri i=1;i<=n;i++) arr[i][0]=val[i]; for(ri i=1;i<=log2(n);i++) { for(ri j=1;j+(1<<i)-1<=n;j++) { arr[j][i]=gcd(arr[j][i-1],arr[j+(1<<(i-1))][i-1]); } } } int qu(int a,b) { int k=log2(b-a+1); return gcd(arr[a][k],arr[r-(1<<(k))+1][k]); }
推荐博客 :浅谈ST表 - 自为风月马前卒 - 博客园 (cnblogs.com)
本题思路:
- 每一次的转化,对于一个基本元素就是 (ai+ai+1+ai+2......)这种对题目的预处理思维很常见的。
- 利用gcd的性质,满足结合律,谁便结合,让他们都相等就是 ai=gcd(all)
- 利用二分求K
- 利用ST判断可行不
#include <bits/stdc++.h> using namespace std; #define ri register int #define M 200005 template <class G > void read(G &x) { x=0;int f=0;char ch=getchar(); while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x=f?-x:x; return ; } int n,m; int T,val[M]; int st[M][30]; int gg; int gcd(int a,int b) { if(a<b) swap(a,b); if(a%b!=0) { return gcd(b,a%b); } else return b; } void init(){ for(ri i=1;i<=n;i++) st[i][0]=val[i]; for(ri i=1;i<=log2(n);i++) { for(ri j=1;j+(1<<i)-1<=n;j++) { st[j][i]=gcd(st[j][i-1],st[j+(1<<(i-1))][i-1]); } } } int qu(int l,int r) { int k=log2(r-l+1); return gcd(st[l][k],st[r-(1<<k)+1][k]); } bool ck(int a) { for(ri i=1;i<=n;i++) { if(i+a<=n) { if(qu(i,i+a)==gg) continue; else return 0; } else { if(gcd(qu(i,n),qu(1,(i+a-n)))==gg) continue; else return 0; } } return 1; } int main(){ read(T); while(T--) { read(n); for(ri i=1;i<=n;i++) { read(val[i]); } bool ff=0; gg=gcd(val[1],val[2]); for(ri i=2;i<=n;i++) { if(val[i]!=val[1]) ff=1; gg=gcd(val[i],gg); } if(ff==0) { printf("0\n"); continue; } init(); int l=1,r=n; while(l<r) { int mid=(l+r)>>1; if(ck(mid)) r=mid; else l=mid+1; } printf("%d\n",l); } }