2023-10-09 模拟赛总结
模拟赛链接
排名:
分数:
终于有一次模拟赛不掉分了。
T1:最后一课 / dist
题目描述:
在一个平面直角坐标系上,给定一条直线
思路:
先考虑最简单的情况,两个点分别在直线两侧,我们知道两点之间线段最短,那么就直接连一条线段即可。
另一种情况两个点在直线同侧,这样就变成了一个经典的题目:将军饮马。我们可以对其中一个点做的对称轴为该直线的对称,再将两点连线,就可以了。
代码:
#include <bits/stdc++.h>
using namespace std;
long long k, xp, yp, xq, yq;
int main() {
freopen("dist.in", "r", stdin);
freopen("dist.out", "w", stdout);
cin >> k >> xp >> yp >> xq >> yq;
(yp >= k) == (yq >= k) && (yq -= (yq - k) * 2);
cout << (xp - xq) * (xp - xq) + (yp - yq) * (yp - yq);
return 0;
}
时间复杂度:
T2:日常 / shoot
题目描述
Kiana 正在基地里打靶。在一条长度为
接下来,Kiana 进行了 Again
,假如没有射在靶子上,输出 Failed
。假如不符合以上两条,且打到了红色区域,则输出 Perfect
,否则输出 Normal
。(
思路:
看到这么多区间,还有多次询问点的状态,很容易想到二分(也可以想到线段树),由于这题的区间没有交集,所以很好处理。先二分找到这个点所在的区间,在看它是否在这个区间里,然后模拟即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int kMaxN = 1e5 + 5;
int n, m, k;
bool vis[kMaxN];
struct Line {
int l, x, y, r;
bool operator<(const Line &y) const {
return l < y.l;
}
} a[kMaxN];
int main() {
freopen("shoot.in", "r", stdin);
freopen("shoot.out", "w", stdout);
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
cin >> a[i].l >> a[i].x >> a[i].y >> a[i].r;
}
sort(a + 1, a + 1 + n);
for (int p, p1; k; k--) {
cin >> p;
p1 = upper_bound(a + 1, a + 1 + n, (Line){p, -1, -1, -1}) - a - 1;
if (a[p1].r < p) {
cout << "Failed\n";
} else if (vis[p1]) {
cout << "Again\n";
} else if (a[p1].x <= p && p <= a[p1].y) {
cout << "Perfect\n", vis[p1] = 1;
} else {
cout << "Normal\n", vis[p1] = 1;
}
}
return 0;
}
时间复杂度:
T3:渡尘 / max
题目描述:
给你一个长度为
思路:
的思路:
我们可以发现绝对值最大子段和就是最大子段和的绝对值和最小子段和的绝对值的最大值,我们对于每一次询问,可以 动态规划求出最大子段和和最小子段和,然后没了。
该算法的时间复杂度:
的思路:
区间查询最大子段和和最小子段和,我们很容易想到用线段树维护区间最大子段和和最小子段和。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int kMaxN = 1e5 + 5;
LL n, m, a[kMaxN];
struct Seg {
LL maxn, minn, premax, sufmax, premin, sufmin, sum;
} t[kMaxN << 2], ans;
void PushUp(Seg& u, Seg& ls, Seg& rs) {
u.premax = max(ls.premax, ls.sum + rs.premax);
u.sufmax = max(rs.sufmax, rs.sum + ls.sufmax);
u.premin = min(ls.premin, ls.sum + rs.premin);
u.sufmin = min(rs.sufmin, rs.sum + ls.sufmin);
u.sum = ls.sum + rs.sum;
u.maxn = max(max(u.premax, u.sufmax), max(ls.sufmax + rs.premax, max(ls.maxn, rs.maxn)));
u.minn = min(min(u.premin, u.sufmin), min(ls.sufmin + rs.premin, min(ls.minn, rs.minn)));
}
void Build(int u, int l, int r) {
if (l == r) {
return (t[u].maxn = t[u].minn = t[u].premax = t[u].sufmax = t[u].premin = t[u].sufmin = t[u].sum = a[l], (void)0);
}
int mid = l + r >> 1;
Build(u << 1, l, mid), Build(u << 1 | 1, mid + 1, r);
PushUp(t[u], t[u << 1], t[u << 1 | 1]);
}
Seg Query(int u, int L, int R, int l, int r) {
if (L <= l && r <= R) {
return t[u];
}
int mid = l + r >> 1;
if (L <= mid && R > mid) {
Seg ls = Query(u << 1, L, R, l, mid), rs = Query(u << 1 | 1, L, R, mid + 1, r), ans;
PushUp(ans, ls, rs);
return ans;
} else if (L <= mid) {
return Query(u << 1, L, R, l, mid);
} else {
return Query(u << 1 | 1, L, R, mid + 1, r);
}
}
int main() {
freopen("max.in", "r", stdin);
freopen("max.out", "w", stdout);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
Build(1, 1, n);
for (int l, r; m; m--) {
cin >> l >> r, ans = Query(1, l, r, 1, n);
cout << max(llabs(ans.maxn), llabs(ans.minn)) << '\n';
}
return 0;
}
该算法的时间复杂度:
的思路:
一、猫树:
我们发现这道题没有修改,用线段树可能有点浪费,于是我们可以用猫树来处理(本人不会猫树,这只是一种做法而已)
该算法的时间复杂度:
二、前缀和 + st 表:
看到连续区间和,首先可以想到用前缀和处理,若查询区间为
再变一下型:
里面的区间最大最小值就可以用 st 表实现了。
代码:
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int kMaxN = 2e5 + 5, kL = 20;
LL n, m, a[kMaxN], f[kMaxN][kL], g[kMaxN][kL], lg[kMaxN];
int main() {
freopen("max.in", "r", stdin);
freopen("max.out", "w", stdout);
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m, lg[0] = -1;
for (int i = 1; i <= n; i++) {
cin >> a[i];
g[i][0] = f[i][0] = (a[i] += a[i - 1]);
lg[i] = lg[i / 2] + 1;
}
lg[n + 1] = lg[(n + 1) / 2] + 1;
for (int j = 1; j < kL; j++) {
for (int i = 0; i <= n - (1 << j) + 1; i++) {
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
g[i][j] = min(g[i][j - 1], g[i + (1 << (j - 1))][j - 1]);
}
}
for (int l, r, t; m; m--) {
cin >> l >> r, l--, t = lg[r - l + 1];
cout << max(f[l][t], f[r - (1 << t) + 1][t]) - min(g[l][t], g[r - (1 << t) + 1][t]) << '\n';
}
return 0;
}
时间复杂度:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异