Magical GCD

Description:

对于一个由正整数组成的序列, Magical GCD 是指一个区间的长度乘以该区间内所有数字的最大公约数。给你一个序列,求出这个序列最大的 Magical GCD。

INPUT:

单个测试点包含多组数据。
输入的第一行是一个整数T表示数据组数。
每组数据的第一行是一个整数N,描述序列长度。
接下来N个数字,描述这个序列元素A[i]。
1
5
30 60 20 20 20

OUTPUT:

对于每组测试数据输出一行,包含一个整数,表示序列最大的 Magical GCD。
80

分析:

题目是要求区间极值,很容易就想到ST算法。
设f[i][j]表示 i i+2j 这个区间中最大的Magical GCD,方程:
f[i][j]=GCD(f[i][j1],f[i+2j1][j1])
时间复杂度 o(nlog(n)) ,哈哈,这题切了。
等会,貌似假如最大的区间长度不是 2x 呢?
貌似会炸……
怎么办???????
我们知道:Magical GCD(l,r)=Magical GCD(Magical GCD(l,x),Magical GCD(y,r))。如图:
Magical GCD_第1张图片
那么我们就可以枚举r,然后二分一个点l,使得Magical GCD(l,r)=a[r], 更新答案,将r移到l,直到r=0为止。
代码不优美的话加一个读入优化就过了(仅限c++),然而我并没有加。

CODE:

#include
#include
#include 
long long  t,n,a[100001],f[100001][17],log[300001];
long long read()
{
    long long l=0;
    char c;
    c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') {l=l*10+c-'0';c=getchar();}
    return l;
}
long long  gcd(long long a,long long b)
{
    long long c;
    while (b>0)
    {
        c=a%b;
        a=b;
        b=c;
    }
    return a;
}
long long max(long long a,long long b)
{
    if (a>b) return(a); else return(b);
}
void work()
{
        //n=read();
        scanf("%lld",&n); 
        long long i,j,k;
        for (i=1;i<=n;i++) 
        {
            //a[i]=read();
            scanf("%lld",&a[i]);
            f[i][0]=a[i];
        }
        long long ans=0;
        for(i=1;i<=log[n];i++)
        {
            for(j=1;j<=n-(1<1;j++)
            {
                f[j][i]=gcd(f[j][i-1],f[j+(1<1)][i-1]);
            }
        }
        for(i=1;i<=n;i++)
        {
            if(ans0]) ans=f[i][0];
            long long x=f[i-1][1];
            int l=1,r=i;
            while(r!=0)
            {
                l=1;
                if(x*i<=ans)break;
                while(l<=r)
                {
                    int mid=(l+r)/2;
                    int len=i-mid+1;
                    if(gcd(f[mid][log[len]],f[i-(1<<log[len])+1][log[len]])!=x)
                        l=mid+1;
                    else
                        r=mid-1;
                }
                ans=max(ans,(i-r)*x);
                if(r>0) x=gcd(x,f[r][0]);
            }
        }
        printf("%lld\n",ans);
}
int main()
{
    long long i=1,j,k=2;
    int y=1;
    while (k<=300000)
    {
        for (j=y;j<=k-1;j++) log[j]=i-1;
        y=k;
        k*=2;
        i++;
    }
    freopen("1.in","r",stdin);
    scanf("%lld",&t);

    for (i=1;i<=t;i++)
    {
        work();
    }
    fclose(stdin);
} 

你可能感兴趣的:(题解,RMQ)