题解:P11845 [USACO25FEB] Min Max Subarrays P
模拟赛考了这个题,被硬控 2h,最后没调出来,问候搬题人母亲。
考虑对于一个长度等于奇数的序列,在上面进行一轮操作,手玩发现很大概率都是得到最大值。
继续手玩发现
考试时对于这个的一种解释:只有
考虑区间长度为偶数,发现很多情况都是取到次大值。
反例手玩就会发现,只会存在于
考虑证明,因为
这样只需要维护所有长度为奇数的区间的最大值和所有长度为偶数的区间的次大值。
这个好(?)维护,直接分治,每次拿个双指针扫就做完了。
真难写,/tuu /tuu /tuu,果然我还是不适合做数据结构,时间
Tips:有大神告诉我,不用分类讨论,直接记搜搜出来
#include <bits/stdc++.h>
#define ll long long
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define pii pair<ll, ll>
#define mp make_pair
#define pb push_back
#define ld lower_bound
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define drep(i, a, b) for (int i = (a); i >= (b); i--)
#define ud upper_bound
#define mem(s, k) memset(s, k, sizeof(s))
#define cpy(s, t) memcpy(s, t, sizeof(s))
#define fi first
#define se second
#define ull unsigned long long
#define vi vector<int>
#define fv inline void
#define fn inline static
using u16 = unsigned short;
using u32 = unsigned;
using u64 = unsigned ll;
using u128 = __uint128_t;
using i16 = short;
using i32 = ll;
using i64 = ll;
using i128 = __int128_t;
using db = double;
using namespace std;
const int N = 1e6 + 5;
i32 ans = 0;
struct info {
i32 mx, se;
info() { mx = se = 0; }
fv ins(i32 x) {
if (mx < x)
se = mx, mx = x;
else if (se < x)
se = x;
}
friend info operator+(info x, info y) {
x.ins(y.mx), x.ins(y.se);
return x;
}
};
i32 n, m, a[N];
info p[N], q[N];
fv calc(i32 n, i32 m) {
i32 pos = 0, t[2] = {};
rep(i, 1, m) {
while (pos < n && p[pos + 1].mx <= q[i].se) t[(++pos) & 1]++;
ans += t[i & 1] * q[i].se;
}
pos = t[0] = t[1] = 0;
rep(i, 1, n) {
while (pos < m && q[pos + 1].mx <= p[i].se) t[(++pos) & 1]++;
ans += t[i & 1] * p[i].se;
}
pos = t[0] = t[1] = 0;
rep(i, 1, m) {
while (pos < n && p[pos + 1].mx <= q[i].mx) t[(++pos) & 1] += p[pos].mx;
ans += t[i & 1];
}
pos = t[0] = t[1] = 0;
rep(i, 1, m) {
while (pos < n && p[pos + 1].mx <= q[i].se) t[(++pos) & 1] += p[pos].mx;
ans -= t[i & 1];
}
pos = t[0] = t[1] = 0;
rep(i, 1, n) {
while (pos < m && q[pos + 1].mx < p[i].mx) t[(++pos) & 1] += q[pos].mx;
ans += t[i & 1];
}
pos = t[0] = t[1] = 0;
rep(i, 1, n) {
while (pos < m && q[pos + 1].mx <= p[i].se) t[(++pos) & 1] += q[pos].mx;
ans -= t[i & 1];
}
}
fv solve(i32 l, i32 r) {
if (l == r)
return;
i32 mid = (l + r) >> 1;
solve(l, mid), solve(mid + 1, r);
i32 n = mid - l + 1, m = r - mid;
p[0] = q[0] = info();
rep(i, 1, n) p[i] = p[i - 1], p[i].ins(a[mid - i + 1]);
rep(i, 1, m) q[i] = q[i - 1], q[i].ins(a[mid + i]);
calc(n, m);
}
i32 L[N], R[N], stk[N], tp;
int main() {
IOS;
freopen("minmax.in", "r", stdin);
freopen("minmax.out", "w", stdout);
cin >> n;
rep(i, 1, n) cin >> a[i];
rep(i, 1, n) {
i32 mxp = -1, secp = -1, mx = -1e9, sec = -1e9, thd = -1e9;
rep(j, i, n) {
if (a[j] > mx)
secp = mxp, mxp = j, thd = sec, sec = mx, mx = a[j];
else if (a[j] > sec)
secp = j, thd = sec, sec = a[j];
else if (a[j] > thd)
thd = a[j];
if (j - i + 1 == 3) {
if (mx == a[i + 1])
ans += max(a[i], a[j]);
else
ans += mx;
} else if (j - i + 1 == 4) {
if (a[i] == mx && a[i + 2] == sec || a[i + 2] == mx && a[i] == sec)
ans += max(a[i + 1], a[i + 3]);
else if (a[i + 1] == mx && a[i + 3] == sec || a[i + 1] == sec && a[i + 3] == mx)
ans += max(a[i], a[i + 2]);
else if (a[i + 1] == mx && a[i + 2] == sec || a[i + 1] == sec && a[i + 2] == mx)
ans += max(a[i], a[i + 3]);
else
ans += sec;
} else if (j - i + 1 == 6) {
if (abs(secp - mxp) == 2 && secp != i && mxp != i && secp != j && mxp != j)
ans += thd;
else if (abs(secp - mxp) == 3 && secp != i && mxp != i && secp != j && mxp != j)
ans += thd;
else
ans += sec;
} else {
if ((j - i + 1) & 1)
ans += mx;
else
ans += sec;
}
ans -= ((j - i + 1) & 1 ? mx : sec);
if (j - i + 1 >= 6)
break;
}
}
solve(1, n);
rep(i, 1, n) {
while (tp && a[stk[tp]] < a[i]) --tp;
L[i] = stk[tp] + 1, stk[++tp] = i;
}
tp = 0;
drep(i, n, 1) {
while (tp && a[stk[tp]] <= a[i]) --tp;
R[i] = tp ? stk[tp] - 1 : n, stk[++tp] = i;
i32 vl = i - L[i], vr = R[i] - i;
i32 p0 = (vl + 2) >> 1, p1 = vl + 1 - p0;
i32 q0 = (vr + 2) >> 1, q1 = vr + 1 - q0;
ans += p0 * q0 * a[i] + q1 * p1 * a[i];
}
cout << ans;
}