题意:
长度为 n 的数组
A 。他定义了一个函数 fl,r,k ,其中 l,r,k 是满足 l≤r 且 r×k≤n 的正整数。函数值等于 p×q×⌊k√ ,其中 p 是Al×k,A(l+1)×k,...,Ar×k 的和值,而 q 是这些数的最小值。YJQQQAQ想要仔细选择l,r,k 以最大化函数值。
思路:
枚举k,得到对应的序列。
然后对于这个序列来说,枚举最小值的位置,看这个最小值往左和往右最长能够延伸的位置,求出对应的和值,这个可以用单调栈来优化!这样就能得到这个序列下,最大的 p∗q 的值,最后取一下 max 就好了。
代码:
#include <cstdio>
#include <iostream>
#include <cmath>
#include <vector>
#define PB push_back
#define FT first
#define SD second
#define MP make_pair
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> P;
const int N = 3e5 + 10,MOD = 7+1e9;
int n, a[N], R[N], L[N], st[N];
LL sum[N];
vector<int> G;
LL gao()
{
int m = G.size();
int top = 0;
for(int i = 0;i < m;++ i) {
L[i] = -1;
R[i] = m;
if(i == 0) sum[i] = G[i];
else sum[i] = sum[i-1] + G[i];
}
for(int i = 0;i < m;++ i) {
if(top == 0) st[top ++] = i;
else {
while(top != 0 && G[st[top-1]] > G[i]) {
R[st[top-1]] = i;
top --;
}
st[top ++] = i;
}
}
top = 0;
for(int i = m - 1;i >= 0;-- i) {
if(top == 0) st[top ++] = i;
else {
while(top != 0 && G[st[top-1]] > G[i]) {
L[st[top-1]] = i;
top --;
}
st[top ++] = i;
}
}
LL ans = 0, tmp;
for(int i = 0;i < m;i ++) {
if(L[i] == -1) tmp = 0;
else tmp = sum[L[i]];
ans = max(ans, 1LL * G[i] * (sum[R[i] - 1] - tmp));
}
return ans;
}
int main()
{
int T;
scanf("%d", &T);
while(T --) {
scanf("%d", &n);
for(int i = 1;i <= n;++ i) scanf("%d", &a[i]);
LL ans = 0;
for(int k = 1;k <= n;k ++) {
G.clear();
for(int i = 1;i * k <= n;i ++) G.PB(a[i * k]);
ans = max(ans, 1LL * gao() * (int)sqrt(k + 0.5));
}
printf("%I64d\n", ans);
}
return 0;
}