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]表示
時間複雜度
等會,貌似假如最大的區間長度不是
貌似會炸……
怎麼辦???????
我們知道: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);
}