算法
显然可知, 最大的权值显然是 \(2 \times n + 1\)
我们也可以发现取最大值时序列的特征:中位数大于 $\frac{n}{2} $ , 且包括整个大序列所有大于中位数的整数以及相等个数的小于中位数的数
所以枚举中位数, 找区间 \([L, R]\) 使得 \(i\) 到 \(n\) 的整数都在区间内, 并且要求这个区间的长度是 \(i\) , 其中 \(i \in \left[{\left\lfloor\frac{n}{2}\right\rfloor, n}\right]\) , 这是好实现的
-
这个序列可能已经不符合要求, 即目前长度超过目标长度
此时没有贡献 -
这个序列可能缺少元素
这时可以向左右扩展
计算 \(l, r\) 为向左右拓展的最大区间
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1000005;
int n;
int p[N];
int L, R;
ll ans;
void chkmax(int &a, int b) { if (a < b) a = b; }
void chkmin(int &a, int b) { if (a > b) a = b; }
int main() {
scanf("%d", &n), L = n, R = 0;
for (int i = 1, x; i <= n; ++i) scanf("%d", &x), p[x] = i;
for (int i = 1; i <= n; ++i) {
chkmin(L, p[n - (i / 2)]), chkmax(R, p[n - (i / 2)]);
int len = R - L + 1;
if (len <= i) {
int l, r;
if (R >= i) l = R - i + 1, r = R; else l = 1, r = i;
ans += min(L - l, n - r) + 1;
}
}
printf("%d %lld", 2 * n + 1, ans);
return 0;
}
总结
递推思想可以优化时间复杂度
注意性质的发现能力