2023年10月30日模拟赛

2023年10月30日模拟赛

混氏新子 蒟蒻

前言

先上链接!link 。今天,感觉其实并不是很难,但是感觉并没有考到最好。有个题有想法但是看起来很难所以没有去实现,后来发现其实很简单。应该胆大心细,沉着应对每一场考试。

题解

T1

这道题,最简单的做法就是筛一遍然后倒着把每一个合数都分解到更小的就行。还有方法就是枚举每一个质数看有多少个。都可以。[[线性筛]]

T2

结论题。只有在直径是奇数时直径中间那个点上 Bob 能赢。我们首先考虑链的情况,就能发现这一点。然后推广到一般的树,发现其它的点都能和直径上的一点对应。完成! [[博弈论]]

T3

其实显而易见要选一个最长的其它都是 1 位,然后开头有不少于 k - 1 个 0 的时候特判一下。但是我不知道为什么觉得这个结论不太对就打暴力了()。还是要注意一下。std 用的是 hash 的方法,但是一眼就感觉能被 hack,但是能过。最正确的方法就是最小表示法或者用 SA 来做。不过 hash 还是好写得多。[[hash]] [[字符串]]

T4

这道题 luogu 上有原题哉!link 。还是黑的哦!所以要怎么做呢?我们一开始应该的想的是区间 dp。但是我们发现样很难转移,而且我们又发现 k 和 n 是同阶的,而且我们发现走一段山峰灯笼区间是连续的,所以我们定义状态表示灯笼区间是,那么肯定能对应山峰的一段区间,然后转移就很方便了。这样会发现复杂度是的,但是我们将 i 按照 a 从小到大排序,j 按照 b 大到小排序,这样我们会发现枚举时左端点确定时区间大小减小,右端点同理。因此我们用堆维护,不合法直接弹出,对后面也不会有任何影响。结合代码看会非常好懂。[[dp]]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <bits/stdc++.h>
using namespace std;
#define N 2010
#define mp make_pair
#define pii pair<int, int>
#define fi first
#define se second
int n, k;
int h[N];
int p[N], c[N], a[N], b[N], al[N], ar[N], bl[N], br[N];
int f[N][N];
int main() {
freopen("lantern.in", "r", stdin);
freopen("lantern.out", "w", stdout);
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i) scanf("%d", h + i);
vector<int> l(k), r(k);
for (int i = 1; i <= k; ++i) {
scanf("%d%d%d%d", p + i, c + i, a + i, b + i);
al[i] = p[i] + 1;
while (al[i] > 1 && h[al[i] - 1] >= a[i]) --al[i];
ar[i] = p[i] - 1;
while (ar[i] < n && h[ar[i] + 1] >= a[i]) ++ar[i];
bl[i] = p[i] + 1;
while (bl[i] > 1 && h[bl[i] - 1] <= b[i]) --bl[i];
br[i] = p[i] - 1;
while (br[i] < n && h[br[i] + 1] <= b[i]) ++br[i];
l[i - 1] = r[i - 1] = i;
}
memset(f, -1, sizeof(f));
sort(l.begin(), l.end(), [&](int x, int y){return mp(a[x], -b[x]) < mp(a[y], -b[y]);});
sort(r.begin(), r.end(), [&](int x, int y){return mp(b[x], -a[x]) > mp(b[y], -a[y]);});
priority_queue<pii, vector<pii>, greater<pii> > lz[N], rz[N];
for (auto i : l) {
for (auto j : r) {
if (a[i] < a[j] && b[j] < b[i]) {
f[i][j] = f[i][i];
} else if (a[j] < a[i] && b[i] < b[j]) {
f[i][j] = f[j][j];
} else if (a[i] <= a[j] && b[i] <= b[j]) {
int z = max(al[i], bl[j]), y = min(ar[i], br[j]);
if (p[i] < z || p[i] > y || p[j] < z || p[j] > y) continue;
if (z == 1 && y == n) {
f[i][j] = 0;
goto nxt;
}
while (!lz[i].empty() && (p[lz[i].top().se] < z || p[lz[i].top().se] > y || a[lz[i].top().se] > b[j])) lz[i].pop();
if (!lz[i].empty()) {
f[i][j] = lz[i].top().fi;
}
while (!rz[j].empty() && (p[rz[j].top().se] < z || p[rz[j].top().se] > y || b[rz[j].top().se] < a[i])) rz[j].pop();
if (!rz[j].empty()) {
(f[i][j] == -1 || f[i][j] > rz[j].top().fi) && (f[i][j] = rz[j].top().fi);
}
}
nxt:
if (~f[i][j]) {
lz[i].emplace(f[i][j] + c[j], j);
rz[j].emplace(f[i][j] + c[i], i);
}
}
}
for (int i = 1; i <= k; ++i) {
printf("%d\n", f[i][i] == -1 ? f[i][i] : f[i][i] + c[i]);
}
return 0;
}

后记

今天天气很黑,外面都是黑的。那看样子是天黑了,害。十月份就过去啦。感觉恍恍惚惚的。好像一直都是恍恍惚惚的。心情看起来也很快乐与舒畅呢。对世界抱有经久不衰的热情与好奇心,怀有一颗童心,积极面对生活。大家也都很认真在用功。我也要努力呀。

  • 标题: 2023年10月30日模拟赛
  • 作者: 混氏新子
  • 创建于 : 2023-10-30 22:54:35
  • 更新于 : 2023-10-30 23:41:20
  • 链接: https://blog.huasushis.cn/2023/2023年10月30日模拟赛/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
此页目录
2023年10月30日模拟赛