JZOJ-senior-3780. 【NOIP2014模拟8.17】Magical GCD

xiaoxiao2023-03-27  26

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是单调不增的考虑枚举右端点 i i i b [ j ] b[j] b[j] 表示区间 [ j , i ] [j,i] [j,i] 的GCD我们发现对于 b [ j ] = = b [ j − 1 ] b[j]==b[j-1] b[j]==b[j1] ,我们只需要保留 j − 1 j-1 j1 ,而不需要 j j j ,为什么呢?既然 b [ j ] = = b [ j − 1 ] b[j]==b[j-1] b[j]==b[j1] ,那么当右端点继续右移时,他们的到右端点的GCD是一样的而 j − 1 j-1 j1 的长度显然更优,那么 j j j 就没有存在的必要,我们用链表维护一下,跳过不必要的区间就好了

如果我的表述不清楚,可以看这个

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); } }
转载请注明原文地址: https://www.6miu.com/read-4988256.html

最新回复(0)