JZOJ-senior-3780. 【NOIP2014模擬8.17】Magical GCD
阿新 • • 發佈:2018-12-18
Time Limits: 2000 ms Memory Limits: 131072 KB
Description
對於一個由正整陣列成的序列, Magical GCD 是指一個區間的長度乘以該區間內所有數字的最大公約數。給你一個序列,求出這個序列最大的 Magical GCD。
Input
單個測試點包含多組資料。 輸入的第一行是一個整數T表示資料組數。 每組資料的第一行是一個整數N,描述序列長度。 接下來N個數字,描述這個序列元素A[i]。
Output
對於每組測試資料輸出一行,包含一個整數,表示序列最大的 Magical GCD。
Sample Input
1 5 30 60 20 20 20
Sample Output
80
Data Constraint
對於 30%分值的資料,N <= 10,T <= 11,000, A[i] <= 100 對於剩餘 70%分值的資料,N <= 100,000,T <= 20, A[i] <= 10^12 C/C++選手讀入和輸出 64 位整數請使用%lld。
Hint
【樣例說明】 對於子區間 60 20 20 20,長度為 4,最大公約數為 20,此段 Magical GCD 為 80.
【評分標準】 對於每個測試點,你的輸出必須和標準輸出一致得到全部分數,否則不得分。
Solution
- 不難發現,固定了左端點後,右端點往右移GCD是單調不增的
- 考慮列舉右端點 , 表示區間 的GCD
- 我們發現對於 ,我們只需要保留 ,而不需要 ,為什麼呢?
- 既然 ,那麼當右端點繼續右移時,他們的到右端點的GCD是一樣的
- 而 的長度顯然更優,那麼 就沒有存在的必要,我們用連結串列維護一下,跳過不必要的區間就好了
如果我的表述不清楚,可以看這個
Code
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=1e5+5;
int T,n,l[N],r[N];
long long ans,a[N],b[N];
long long gcd(long x,long y)
{
return y?gcd(y,x%y):x;
}
int main()
{
freopen("magical.in","r",stdin);
freopen("magical.out","w",stdout);
scanf("%d",&T);
while(T--)
{
scanf("%d",&n),ans=0;
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]),b[i]=a[i];
l[i]=i-1,r[i]=i+1;
}
for(int i=1;i<=n;++i)
for(int j=1;j<=i;j=r[j])
{
b[j]=gcd(b[j],a[i]);
ans=max(ans,b[j]*(i-j+1));
if(b[j]==b[j-1]) r[l[j]]=r[j],l[r[j]]=l[j];
}
printf("%lld\n",ans);
}
}