题意:给定长度为n的数列,求这个数列的所有子区间中子区间长度与子区间最大公约数乘积的最大值。
思路:存在一个求区间最大公约数的模板,其思想是固定区间的右端点,依次向左寻找与右端点产生不同最大公约数的点。可在nlogA时间复杂度内完成求所有子区间的不同的最大公约数。A是数列中的最大值。
for (int i = 1; i <= n; i++) {
ll x = val[i];
ll y = i;
g[i].push_back(make_pair(x, y));
for (int j = 0; j < g[i - 1].size(); j++) {
pair<ll, ll> p = g[i - 1][j];
ll gcd = calGcd(x, p.first);
if (gcd != x) {
x = gcd;
y = p.second;
g[i].push_back(make_pair(x, y));
}
}
}
p.first存储的是最大公约数,p.second存储的是左端点的索引。
AC代码:
#include <iostream>
#include <vector>
using namespace std;
const int MAXN = 100005;
typedef long long ll;
vector<pair<ll, ll> > g[MAXN];
ll val[MAXN];
ll calGcd(ll a, ll b) {
if (b == 0) {
return a;
}
return calGcd(b, a % b);
}
int main() {
int T;
cin >> T;
while (T-- != 0) {
int n;
cin >> n;
g[0].clear();
for (int i = 1; i <= n; i++) {
cin >> val[i];
g[i].clear();
}
for (int i = 1; i <= n; i++) {
ll x = val[i];
ll y = i;
g[i].push_back(make_pair(x, y));
for (int j = 0; j < g[i - 1].size(); j++) {
pair<ll, ll> p = g[i - 1][j];
ll gcd = calGcd(x, p.first);
if (gcd != x) {
x = gcd;
y = p.second;
g[i].push_back(make_pair(x, y));
}
}
}
ll res = 0;
for (int i = 1; i <= n; i++) {
pair<ll, ll> p1, p2;
for (int j = 0; j < g[i].size() - 1; j++) {
p1 = g[i][j];
p2 = g[i][j + 1];
res = max(res, p1.first * (i - p2.second));
}
p1 = g[i][g[i].size() - 1];
res = max(res, (ll)(i) * p1.first);
}
cout << res << endl;
}
return 0;
}