2025CSP-S模拟赛34 比赛总结
2025CSP-S模拟赛34
| T1 | T2 | T3 | T4 |
|---|---|---|---|
| 50 TLE | 10 RE | 0 WA | 20 TLE |
总分:80;排名:12/17。
什么情况呢?T1 暴力,T2 暴力写挂了,T3 暴力没写出来,T4 暴力。
T1 酒吧
首先一个 \(O(n^2)\) 的 dp 是显然的。然后考虑优化。我们发现他首先不可单调队列优化,然后发现他不满足决策单调性也不满足凸性,然后发现也难以线段树维护,然后我们就失败了。
考虑正解。首先,显然选 \(1\) 和 \(n\) 是不劣的。我们假设我们选了 \(b_1,b_2,\dots,b_n\) 这些位置,那么 \(ans=\sum(b_{i+1}-b_i)\times(p_{b_i}+p_{b_{i+1}})\)。然后我们把 \((i,p_i)\) 扔到平面直角坐标系上,你就发现这个答案式子可以搞成几个梯形的面积和,然后你就发现答案就是这几个点的连线与 \(x\) 轴组成的封闭图形的面积之和。那么显然选一个上凸包是最优的,然后你维护个凸包就搞完了。不是哥们,这是人类能想到的吗。。
#include <bits/stdc++.h>
#define il inline
#define int long long
using namespace std;
const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
int x = 0; char ch = getchar(); bool t = 0;
while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
return t ? -x : x;
}
const int N = 5e5 + 10;
int n, a[N];
int q[N], tail;
il int x(int i) {return i;}
il int y(int i) {return a[i];}
il double slope(int i, int j) {
return 1.0 * (y(i) - y(j)) / (x(i) - x(j));
}
signed main() {
freopen("bar.in", "r", stdin);
freopen("bar.out", "w", stdout);
n = read();
for (int i = 1; i <= n; i++) {
a[i] = read();
}
q[++tail] = 1;
for (int i = 2; i <= n; i++) {
while (tail > 1 && slope(q[tail - 1], q[tail]) < slope(q[tail], i)) tail--;
q[++tail] = i;
}
int ans = 0;
for (int i = 1; i < tail; i++) {
ans += (q[i + 1] - q[i]) * (a[q[i + 1]] + a[q[i]]);
}
printf("%lld\n", ans);
return 0;
}
T2 逆转
不会写二分了。
显然答案具有单调性。然后考虑二分这个答案,然后判断是否能达到这个答案。
考虑如何判断。考虑枚举断点。我们在前一半统计至多能选多少个数使得其加和 \(\le mid\),后一半做一样的统计。至于如何统计,搞一个主席树在权值线段树上二分即可。
#include <bits/stdc++.h>
#define il inline
#define int long long
using namespace std;
const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
int x = 0; char ch = getchar(); bool t = 0;
while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
return t ? -x : x;
}
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 3e5 + 10;
int n, kk, a[N], b[N];
int root[N];
struct node {
int l, r, s, val;
} tree[N << 5];
#define lc tree[p].l
#define rc tree[p].r
int tot;
il void build(int &p, int l, int r) {
if (!p) p = ++tot;
if (l == r) return;
int mid = l + r >> 1;
build(lc, l, mid), build(rc, mid + 1, r);
}
il void pushup(int p) {
tree[p].s = tree[lc].s + tree[rc].s;
tree[p].val = tree[lc].val + tree[rc].val;
}
il int update(int p, int l, int r, int x, int v) {
int rt = ++tot;
tree[rt] = tree[p];
if (l == r) {
tree[rt].val += v;
tree[rt].s += v * b[l];
return rt;
}
int mid = l + r >> 1;
if (x <= mid) tree[rt].l = update(lc, l, mid, x, v);
else tree[rt].r = update(rc, mid + 1, r, x, v);
pushup(rt);
return rt;
}
il int query(int p, int q, int l, int r, int x) {
if (l == r) {
return min(x / b[l], tree[q].val - tree[p].val);
}
int mid = l + r >> 1;
int s = tree[tree[q].l].s - tree[tree[p].l].s;
if (x <= s) return query(tree[p].l, tree[q].l, l, mid, x);
else return tree[tree[q].l].val - tree[tree[p].l].val + query(tree[p].r, tree[q].r, mid + 1, r, x - s);
}
il bool check(int num) {
for (int i = 1; i < n; i++) {
if (query(root[0], root[i], 1, n, num) + query(root[i], root[n], 1, n, num) >= kk) {
return true;
}
}
return false;
}
signed main() {
freopen("ace.in", "r", stdin);
freopen("ace.out", "w", stdout);
n = read(), kk = read();
for (int i = 1; i <= n; i++) {
a[i] = read();
b[i] = a[i];
}
sort(b + 1, b + 1 + n);
int ll = unique(b + 1, b + 1 + n) - b - 1;
build(root[0], 1, n);
for (int i = 1; i <= n; i++) {
a[i] = lower_bound(b + 1, b + 1 + ll, a[i]) - b;
root[i] = update(root[i - 1], 1, n, a[i], 1);
}
int L = 0, R = 3e14, ans = 0;
while (L <= R) {
int mid = L + R >> 1;
if (check(mid)) {
ans = mid;
R = mid - 1;
} else {
L = mid + 1;
}
}
printf("%lld\n", ans);
return 0;
}

浙公网安备 33010602011771号