/** 题目:Magical GCD UVA 1642 链接:https://vjudge.net/problem/UVA-1642 题意:给定n个数,求使连续的一段序列的所有数的最大公约数*数的数量的值最大。输出这个最大值。 思路: 从左到右枚举一段连续序列时候,同时不断取gcd,会发现gcd相同的部分。 gcd的值会随着长度边长非递增变化。最多logx个不同的gcd。那么对于一个长长的序列。 要是可以将相同gcd的一起处理,那么时间就可以优化。 枚举姿势要正确,保证当前枚举的位置,可以利用前面的结果。 常规枚举姿势,右边界位置从左到右枚举,然后枚举左边界位置j<=i从右往左枚举。 用d,l两个数组存储信息。 ll d[maxn];//d[i]表示到达i这个位置的最大公约数 ll l[maxn];//l[i]表示i这个位置到l[i]这个位置的最大公约数相同。 */ #include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<vector> #include<set> #include<cmath> using namespace std; typedef long long ll; typedef unsigned long long ull; const int inf = 0x3f3f3f3f; const int maxn = 1e5+100; ll d[maxn];//d[i]表示到达i这个位置的最大公约数 ll l[maxn];//l[i]表示i这个位置到l[i]这个位置的最大公约数相同。 int T, n; ll a[maxn]; ll GCD(ll a,ll b) { return b==0?a:GCD(b,a%b); } int main() { cin>>T; while(T--) { scanf("%d",&n); for(int i = 1; i <= n; i++) scanf("%lld",&a[i]); ll ans = 0; for(int i = 1; i <= n; i++){ d[i] = a[i]; l[i] = i; ll gcd = a[i]; ll pos = l[i]; ll lastpos = pos; ans = max(ans,a[i]); pos--; while(pos>=1){ pos = l[pos]; ll gcdl = GCD(gcd,d[pos]); ans = max(ans,gcdl*(i-pos+1)); if(gcdl==gcd){ l[lastpos] = pos; d[pos] = gcdl; }else { gcd = gcdl; lastpos = pos; d[pos] = gcdl; } pos--; } } printf("%lld ",ans); } return 0; }