还想小号上分来着,结果F题翻车,最后两分钟才绝杀F,导致水题没切,上分变上坟了
题意:有n个木板,每个木头都有高度和提升一个单位高度的花费,一个木头可以多次提升高度,要求相邻木头高度不能相同,求最少总花费。
解法:因为只是要求相邻木头不能等高,所以每个木头最多只用升两次高度就行,那我们设 为前 个木头合法且第 个木头升了 次高度的最小花费,我们对于第 个木头,枚举其升级次数 ,枚举第 个木头,枚举升级次数 ,显然
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 3e5 + 10;
ll d[maxn][3], inf = 1e18;
int a[maxn], b[maxn];
void up(ll &x, ll y) {
x = min(x, y);
}
ll solve() {
int n;
scanf("%d", &n);
scanf("%d%d", &a[1], &b[1]);
d[1][1] = b[1];
d[1][2] = 2ll * b[1];
for (int i = 2; i <= n; i++) {
scanf("%d%d", &a[i], &b[i]);
d[i][0] = d[i][1] = d[i][2] = inf;
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++)
if (a[i] + j != a[i - 1] + k)
up(d[i][j], d[i - 1][k] + j * b[i]);
}
ll ans = inf;
for (int i = 0; i < 2; i++)
up(ans, d[n][i]);
return ans;
}
int main() {
int T;
scanf("%d", &T);
while (T--)
printf("%lld\n", solve());
}
题意:给出一些平面内带权值的点,现在要你选择一个正方形,要求正方形的正对角线和 重合,然后定义正方形权值:方形内所有点权之和 - 正方形边长,求出权值最大的正方形
解法:我们可以把所有点投影到 上排个序,假设顺着 走到了 ,定义 为矩形 内的所有点总权值, 为矩形 内的所有点总权值,设 为矩形 的总权值,设 为固定右上角为 时所能得到的正方形的最大的权值,我们枚举正方形左下端点 容斥一下下:
,去掉一些常量化简一下:
,这一步可能很多大佬都能一眼看出来了,直接线段树维护 的最大值即可,离散化一下下就so easy咯
#include<bits/stdc++.h>
#define ll long long
#define ls o * 2
#define rs o * 2 + 1
#define mid (l + r) / 2
using namespace std;
const int maxn = 1e6 + 1;
ll inf = 1e18;
int X[maxn];
vector<int> G[maxn];
struct seg {
int pos;
ll mx, tag;
seg operator+(const seg& t) const {
seg tmp;
tmp.mx = max(mx, t.mx);
if (mx >= t.mx)
tmp.pos = pos;
else
tmp.pos = t.pos;
return tmp;
}
} tree[maxn * 4];
void build(int o, int l, int r) {
if (l == r) {
tree[o].pos = l;
tree[o].tag = tree[o].mx = 0;
return;
}
build(ls, l, mid);
build(rs, mid + 1, r);
tree[o] = tree[ls] + tree[rs];
}
void pushdown(int o) {
if (tree[o].tag) {
ll tag = tree[o].tag;
tree[ls].tag += tag;
tree[rs].tag += tag;
tree[ls].mx += tag;
tree[rs].mx += tag;
tree[o].tag = 0;
}
}
void up(int o, int l, int r, int ql, int qr, ll v) {
if (l >= ql && r <= qr) {
tree[o].mx += v;
tree[o].tag += v;
return;
}
pushdown(o);
if (ql <= mid)
up(ls, l, mid, ql, qr, v);
if (qr > mid)
up(rs, mid + 1, r, ql, qr, v);
tree[o] = tree[ls] + tree[rs];
}
seg qu(int o, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr)
return tree[o];
pushdown(o);
if (qr <= mid)
return qu(ls, l, mid, ql, qr);
else if (ql > mid)
return qu(rs, mid + 1, r, ql, qr);
else return qu(ls, l, mid, ql, qr) + qu(rs, mid + 1, r, ql, qr);
}
int x[maxn], y[maxn], w[maxn];
int main() {
int n, sz = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d%d%d", &x[i], &y[i], &w[i]);
X[++sz] = x[i];
X[++sz] = y[i];
}
sort(X + 1, X + 1 + sz);
sz = unique(X + 1, X + 1 + sz) - X - 1;
for (int i = 1; i <= n; i++) {
x[i] = lower_bound(X + 1, X + 1 + sz, x[i]) - X;
y[i] = lower_bound(X + 1, X + 1 + sz, y[i]) - X;
G[max(x[i], y[i])].push_back(i);
}
build(1, 1, sz);
ll ans = 0, cat = 0;
int x1 = 2e9, x2 = 2e9;
for (int i = 1; i <= sz; i++) {
for (auto id : G[i]) {
cat += w[id];
int k = max(x[id], y[id]);
up(1, 1, sz, k, sz, w[id]);
up(1, 1, sz, x[id], sz, -w[id]);
up(1, 1, sz, y[id], sz, -w[id]);
}
if (i != 1) {
seg tmp = qu(1, 1, sz, 1, i - 1);
ll res = tmp.mx + cat - X[i];
if (res > ans) {
ans = res;
x1 = X[tmp.pos + 1];
x2 = X[i];
}
}
if (cat - (X[i] - X[1]) > ans) {
ans = cat - (X[i] - X[1]);
x1 = X[1];
x2 = X[i];
}
up(1, 1, sz, i, i, X[i + 1]);
}
printf("%lld\n%d %d %d %d", ans, x1, x1, x2, x2);
}