【JZOJ3780】【UVA1642】Magical GCD
题目大意:
给一个长度为 \(n\) 的数列,找到一个连续子序列使得子序列的公约数与长度的乘积最大,求这个最大值。
正文:
直接枚举 GCD 区间的右端点 \(r\),再枚举左端点 \(l(l<r)\) 计算 GCD,记录答案。
\(\texttt{50}\) 分。
可以通过上一个枚举的右端点 \((r-1)\) 计算过的 GCD 区间更新当前区间就可以了,这些操作可以通过链表实现。
代码:
for (scanf ("%d", &t); t--; )
{
memset (a, 0, sizeof(a));
memset (b, 0, sizeof(b));
memset (last_, 0, sizeof(last_));
memset (next_, 0, sizeof(next_));
ans = 0;
scanf ("%lld", &n);
for (int i = 1; i <= n; i++)
{
scanf ("%lld", &a[i]);
b[i] = a[i];
last_[i] = i - 1, next_[i] = i + 1;
}
for (int r = 1; r <= n; r++)
{
for (int l = 1; l <= r; l = next_[l])
{
b[l] = gcd(b[l], a[r]);
ans = max(ans, (r - l + 1) * b[l]);
if(b[l] == b[last_[l]])
{
next_[last_[l]] = next_[l];
last_[next_[l]] = last_[l];
}
}
}
printf("%lld\n", ans);
}