题目描述

题目传送门

思路

考虑分治。

要求 [l,r][l,r] 的答案,之需求下面三部分答案的最大值(set mid=l+r2mid = \frac{l+r}{2}):

  • [l,mid][l, mid] 的答案;

  • [mid+1,r][mid+1,r] 的答案;

  • a[l,mid],b[mid+1,r],[a,b]{a\in[l,mid], b \in [mid+1,r]},[a,b] 的答案最大值。

这样前两者可以递归解决,考虑如何解决最后一个。

经典结论:一个序列的前缀(后缀)gcd\gcd 最多有 logn\log n 种取值。

那么我们可以预处理 [l,mid][l,mid] 的每个不同的后缀 gcd\gcd 的下标的最小值,[mid+1,r][mid+1,r] 的每个不同的前缀 gcd\gcd 的下标的最大值。然后只需要枚举即可。

时间复杂度为 Θ(nlogn)+Θ(log2n)=Θ(nlogn)\Theta(n \log n) + \Theta(\log^2 n) = \Theta(n \log n)

T(n)T(n) 为时间复杂度。

T(n)=2T(n2)+Θ(nlogn)T(n) = 2{T(\frac{n}{2})}+ \Theta(n \log n)

根据 master 定理,T(n)=Θ(nlogn)T(n) = \Theta(n \log n)

代码

#include <bits/stdc++.h>
using namespace std;

namespace io {
	const int SIZE = (1 << 21) + 1;
	char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
	// getchar
	#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
	// print the remaining part
	inline void flush () {
		fwrite (obuf, 1, oS - obuf, stdout);
		oS = obuf;
	}
	// putchar
	inline void putc (char x) {
		*oS ++ = x;
		if (oS == oT) flush ();
	}
	// input a signed integer
	template <class I>
	inline void read (I &x) {
		for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
		for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;
	}
	// print a signed integer
	template <class I>
	inline void print (I x) {
		if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;
		while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
		while (qr) putc (qu[qr --]);
	}
	struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: read;
using io :: putc;
using io :: print;

const int MAXN = 1e5 + 10;
typedef long long ll;

int T, n;
ll a[MAXN];
vector<pair<ll, int> > p1, p2;

ll Solve(int l, int r) {
	if (l == r) return a[l];
	if (l > r) return 0;
	int mid = l + r >> 1;
	ll res1 = Solve(l, mid), res2 = Solve(mid + 1, r), res3 = 0;
	p1.clear(); p2.clear();
	
	ll tmp1 = a[mid], tmp2;
	for (int i = mid - 1; i >= l; i--) {
		tmp2 = __gcd(tmp1, a[i]);
		if (tmp2 != tmp1) {
			p1.push_back({tmp1, i + 1});
			tmp1 = tmp2;
		}
	}
	p1.push_back({tmp1, l});
	
	tmp1 = a[mid + 1];
	for (int i = mid + 2; i <= r; i++) {
		tmp2 = __gcd(tmp1, a[i]);
		if (tmp2 != tmp1) {
			p2.push_back({tmp1, i - 1});
			tmp1 = tmp2;
		}
	}
	p2.push_back({tmp1, r});
	
	for (auto i : p1) {
		for (auto j : p2) {
			res3 = max(res3, __gcd(i.first, j.first) * (ll)(j.second - i.second + 1));
		}
	}
	return max({res1, res2, res3});
}

int main () {
	read(T);
	while (T--) {
		read(n);
		for (int i = 1; i <= n; i++) read(a[i]);
		print(Solve(1, n));
		putc('\n');
	}
	return 0;
}