Array Stabilization (GCD version)(ST表+二分+题目大意的处理+gcd)

ST

  • (利用二进制进行跳(优化时间复杂度))(预处理 nlogn) 查询 O(1); 
  • 处理 RMQ和GCD问题(重复计算部分无所谓)

arr[i][j] 代表 i —— i+(1<<j)-1 这一区间的值, 区间长度为 1<<j.

log2一定要自己写,不要在调用函数了,地推的思想; 直接调用时 log2的复杂度,不是O1;

 for(int i = 2; i <= n; i++){
        lg2[i] = lg2[i >> 1] + 1;
    }
View Code

 

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]);
 } 
 
View Code

 

 

推荐博客 :浅谈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);
    }
    
} 
View Code

 

posted @ 2022-04-13 20:50  VxiaohuanV  阅读(22)  评论(0编辑  收藏  举报