正睿 2024 CSP 7 连测 Day 7
T1
小A生活在一个庄园中。庄园可以看成一个平面,我们将这个平面划分为单元格。每对整数\((x, y)\)对应一个单元格,我们称这个单元格为单元格\((x, y)\)。每个单元格要么是空地,要么是墙体。
现在给出两个长为\(n\)的正整数序列:\(l_1, l_2, \dots, l_n\)和\(u_1, u_2, \dots, u_n\)。其中对任意的\(i = 1, 2, \dots, n\)都有\(l_i \le u_i\)。所有的单元格\((x, y)\) (\(1 \le x \le n, l_x \le y \le u_x\))都是空地,所有其他的单元格都是墙体。
当小A站在空地\((x, y)\)上时,他可以做出下列动作之一:
- 如果单元格\((x+1, y)\)是空地,移动到单元格\((x+1, y)\)。
- 如果单元格\((x-1, y)\)是空地,移动到单元格\((x-1, y)\)。
- 如果单元格\((x, y+1)\)是空地,移动到单元格\((x, y+1)\)。
- 如果单元格\((x, y-1)\)是空地,移动到单元格\((x, y-1)\)。
庄园当然是连通的,即小A可以通过重复这些动作在任两个空地之间走动。
小A喜欢在庄园里闲逛,但是庄园太大了,他不希望走太长的距离。他进行了\(q\)次询问,对于第\(i\)次询问,给出四个正整数\(s_{x,i}, s_{y,i}, t_{x,i}, t_{y,i}\)。请计算从单元格\((s_{x,i}, s_{y,i})\)走到单元格\((t_{x,i}, t_{y,i})\)至少需要移动几次。保证每次询问给出的两个单元格都是空地。
模拟即可。
const int MAXN = 5e3 + 5;
int n, l[MAXN], r[MAXN], q;
void work() {
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> l[i] >> r[i];
cin >> q;
while (q--) {
int sx, sy, tx, ty;
cin >> sx >> sy >> tx >> ty;
if (sx > tx) {
swap(sx, tx); swap(sy, ty);
}
int y = sy, ans = 0;
for (int i = sx + 1; i <= tx; ++i) {
if (l[i] <= y && y <= r[i]) continue;
if (r[i] < y) {
ans += y - r[i]; y = r[i];
} else {
ans += l[i] - y; y = l[i];
}
}
ans += abs(sx - tx) + abs(ty - y);
cout << ans << endl;
}
}
T2
小B来到了一家珠宝店,珠宝店有 \(n\) 种珠宝,每种珠宝只有一个,其中第 \(i\) 种珠宝价格为 \(w_i\) 元,美丽度为 \(v_i\)。在进入珠宝店之前,小B手里有 \(W\) 元钱,小B想用这些钱来购买珠宝使得美丽度的总和最大。
有趣的是,珠宝店正在进行促销,顾客可以挑选任意 \(k\) 个珠宝免费取走。假设小B使用了最佳策略,请计算他最多能获得多少美丽度。注意,每种珠宝只有一个。
根据交换法可知最优解满足我们免费取的所有物品的重量都要大于我们付费买的物品。
所以我们可以将物品从大到小排序,初始时免费拿所有物品中价值最大的 \(k\) 个,然后挨个加入到背包中。
复杂度 \(O(nm+nk\log n)\)。
const int MAXN = 1e4 + 5;
int n, m, k, f[MAXN];
struct _node {
int v, w;
bool operator < (const _node b) const {
return w < b.w;
};
} a[MAXN];
struct _node2 {
int id, v;
bool operator < (const _node2 b) const {
if (v == b.v) return id < b.id;
return v < b.v;
}
};
set<_node2> st, st2;
void work() {
cin >> n >> m >> k;
for (int i = 1; i <= n; ++i) {
cin >> a[i].w >> a[i].v;
}
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; ++i) {
st2.insert({i, a[i].v});
st.insert({i, a[i].v});
if ((int)st.size() <= k) {
continue;
} else {
st.erase(st.begin());
}
}
int sum = 0, ans = 0;
for (auto it:st) {
if (st2.find({it.id, it.v}) != st2.end()) {
st2.erase(st2.find({it.id, it.v}));
}
sum += it.v;
}
ans = max(ans, sum);
for (int i = 1; i <= n - k; ++i) {
if (st2.find({i, a[i].v}) != st2.end()) st2.erase({i, a[i].v});
if (st.find({i, a[i].v}) != st.end()) {
st.erase(st.find({i, a[i].v}));
sum -= a[i].v;
st.insert({st2.rbegin()->id, st2.rbegin()->v});
sum += st2.rbegin()->v;
st2.erase(prev(st2.end()));
}
for (int j = m; j >= 1; --j) {
if (j >= a[i].w) f[j] = max(f[j], f[j - a[i].w] + a[i].v);
ans = max(ans, f[j] + sum);
}
}
cout << ans << endl;
}
T3
小C也生活在庄园中,有一天,她给一个由 \(n\) 块瓷砖组成的环涂色。瓷砖按顺时针从 \(0\) 到 \(n-1\) 编号。庄园中的颜料只有两种颜色——红色和蓝色,分别用 \(0\) 和 \(1\) 表示。
小C喜欢不同颜色交替出现。环中连续若干块瓷砖的颜色如果是交替颜色 (也就是说这组瓷砖中除了第一块和最后一块瓷砖以外,中间瓷砖的颜色与它左边和右边的颜色都不同),那么它被称为一个交替组。
初始时,编号为 \(i\) 的瓷砖颜色是 \(c_i\)。你需要处理两种类型的操作:
1 u, 确定大小为 \(u\) 的交替组的数量。2 x y, 将编号为 \(x\) 的瓷砖涂成颜色 \(y\)。注意第一块瓷砖和最后一块瓷砖是相邻的。
T4
小D是一名记者,她来到一座小镇进行专题采访。小镇有\(n\)座房子,由\(m\)条双向道路连接,房子从\(1\)到\(n\)编号。小D事先对采访内容作了规划,在她的规划中,有些道路是必经道路,其他道路是可选道路。
小D不希望走重复的路,并且希望采访结束后回到起点。具体地,小D希望找到一条满足下列条件的回路:
- 回路从某个房子出发,经过若干条道路后再回到同一座房子;
- 一条道路不能重复经过(即使方向不同);
- 每条必经道路恰好经过一次。
图可能有重边和自环,如果多条重边都是必经道路,那么符合要求的回路必须经过其中的每一条。
小镇的道路具有特殊的性质:
- 必经道路连通所有的房子,即可以仅经过必经道路从任意一座房子到达任意另一座房子;
- 对于任意的正整数\(k\),不存在\(k\)座房子,两个端点都在这\(k\)座房子中的可选道路超过\(k\)条。
想到可能不存在符合要求的回路,小D提前联系了小镇的祭司。祭司可以在任意两座房子之间打出特殊通道(即便这两座房子之间已经有道路连接),小D可以穿过特殊通道从一座房子到达另一座房子,同时特殊通道销毁。
小D想知道至少需要打出几条 特殊通道。在特殊通道数量最少的基础上,小D还想知道符合要求的回路至少要经过几条可选道路。鉴于这个问题比较复杂,小D会指定其中一个问题,并希望你给出答案。

浙公网安备 33010602011771号