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]表示ii+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))。如圖:
這裏寫圖片描述
那麼我們就可以枚舉r,然後二分一個點l,使得Magical GCD(l,r)=a[r], 更新答案,將r移到l,直到r=0爲止。
代碼不優美的話加一個讀入優化就過了(僅限c++),然而我並沒有加。

CODE:

#include<cstdio>
#include<cstring>
#include<algorithm> 
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<<i)+1;j++)
            {
                f[j][i]=gcd(f[j][i-1],f[j+(1<<i-1)][i-1]);
            }
        }
        for(i=1;i<=n;i++)
        {
            if(ans<f[i][0]) 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);
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章