这里的 购买一组 并不是指购买连续的一段,而是购买一个子序列,即选取一些可以不连续的土地进行购买。
幽默的是,如果根据样例理解的话,基本可以自然地理解成第一种意思。比如我。
于是你迅速写出来了转移方程,然后轻松的看出来了这有决策单调性,愉快的过了样例准备提交后发现只能过一个点。
希望大家不要重蹈覆辙。
失败的 code
// ubsan: on
// accoders
// ????????, ???????
//#pragma GCC optimize(1)
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
//#pragma GCC optimize("Ofast", "inline", "-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
typedef long long LL;
#define int LL
using namespace std;
const int maxn = 5e4 + 10;
LL f[maxn];
int n;
int a[maxn], b[maxn];
int hh, tt;
struct Node {
int p, l, r;
} q[maxn];
struct st_table {
int st[maxn][20];
inline void pre() {
for(int i = 1; 1 << i <= n; ++ i)
for(int j = 1; j + (1 << i) - 1 <= n; ++ j) {
st[j][i] = max(st[j][i - 1], st[j + (1 << i - 1)][i - 1]);
}
}
inline int Q(int l, int r) {
int g = __lg(r - l + 1);
return max(st[l][g], st[r - (1 << g) + 1][g]);
}
} st1, st2;
inline LL w(int l, int r) {
if(l > r) return 0LL;
return 1LL * st1.Q(l, r) * st2.Q(l, r);
}
inline int g(int j, int i) {
return f[j] + w(j + 1, i);
}
inline void force() {
for(int i = 1; i <= n; ++ i) {
int p = 0;
for(int j = 0; j < i; ++ j) {
if(g(j, i) <= g(p, i)) p = j;
}
f[i] = g(p, i);
cout << p << ' ';
}
cout << '\n';
for(int i = 1; i <= n; ++ i) cout << f[i] << ' '; cout << '\n';
return ;
}
signed main() {
cin >> n;
for(int i = 1; i <= n; ++ i) {
cin >> a[i] >> b[i];
st1.st[i][0] = a[i];
st2.st[i][0] = b[i];
}
st1.pre(), st2.pre();
q[tt = 0] = {0, 1, n};
for(int i = 1; i <= n; ++ i) {
while(hh <= tt && q[hh].r < i) hh ++ ;
f[i] = g(q[hh].p, i);
while(hh <= tt && g(i, q[tt].l) < g(q[tt].p, q[tt].l)) tt -- ;
if(hh > tt) {
q[++ tt] = {i, i + 1, n};
continue;
}
int l = q[tt].l, r = n + 1;
while(l < r) {
int mid = l + r >> 1;
if(g(i, mid) <= g(q[tt].p, mid)) r = mid;
else l = mid + 1;
}
if(l > n) continue ;
q[tt].r = l - 1;
q[++ tt] = {i, l, n};
}
cout << f[n] << '\n';
return 0;
}