2025-10-21 XiaoQuQu 的 2025 CSP-S 第二轮模拟 ROUND2 补题
A.set
原题链接:题目详情 - 单调菜单 - XiaoQuQu 的 2025 CSP-S 第二轮模拟 ROUND2 - ZYZOJ
题目:由于禧运楼处于数字世界,所以对于每一种菜品,我们可以用一个整数来描述它的味道。 对于一个由若干种菜品组成的菜单S,我们称这个菜单是单调的当且仅当存在两个菜品,满足
。 现在梨安推出了n种菜品,第i种菜品的味道是a[i]。现在请你对于每一个a的前缀a[1],a[2],…,a[k],求出最多能选多少种菜品,满足这些菜品组成的菜单不是单调的.
分析:我们很直观地看出,对于一些连续段,我们定义它的长度为len,它对答案的贡献为,或者也可以理解为在一段连续区间中奇数与偶数个数地较大值。
那么我们就需要知道对于每个i,一共有多少连续段,且在出入的过程中,当两数之差小于1时,我们要把它们合并为1个连续段,所以我们需要一个支持合并的数据结构——并查集,那么就只剩下写代码了。
正解:
#include <bits/stdc++.h>
using namespace std;
const int N = 500005;
int fa[N], a[N];
int sz[2][N];
bool vis[N];
int n, ans;
int getfa(int x){return (x == fa[x]) ? fa[x] : fa[x] = getfa(fa[x]);
}
void merge(int x, int y){ //sz[1/0][i]表示i区间奇数/偶数的个数x = getfa(x);y = getfa(y);ans -= max(sz[1][x], sz[0][x]);ans -= max(sz[1][y], sz[0][y]);ans += max(sz[1][x] + sz[1][y], sz[0][x] + sz[0][y]);sz[1][x] += sz[1][y];sz[0][x] += sz[0][y];fa[y] = x;
}
int main(){freopen("set.in", "r", stdin);freopen("set.out", "w", stdout);cin >> n;for (int i = 1; i <= n; i++){cin >> a[i];if (vis[a[i]]){cout << ans << " ";continue;}fa[a[i]] = a[i];vis[a[i]] = true;if (a[i] % 2 == 1)sz[1][a[i]] = 1;elsesz[0][a[i]] = 1;ans++;if (vis[a[i] + 1])merge(a[i] + 1, a[i]);if (vis[a[i] - 1])merge(a[i] - 1, a[i]);cout << ans << " "; }
}
B.motor
原题链接:题目详情 - 城市兜风 - XiaoQuQu 的 2025 CSP-S 第二轮模拟 ROUND2 - ZYZOJ
题目:恬豆在禧运楼里翻出了父母留下的一台破旧的摩托车。虚拟上海的地图可以看成是一个 n × m 的网格,其中有 k 座建筑物,分别位于的位置。禧运楼位于位置 (1, 1)。 现在恬豆想要从禧运楼出发,开着这台摩托车去兜风。但由于摩托车比较破旧,所以最多可以启动两次。每次摩托车启动时,恬豆可以选择一个方向并沿着这个方向行走任意长度。当然,路上不能有任何建筑物,否则摩托车就会撞上去。现在恬豆想要知道,一共有多少个位置
是她可以骑着摩托车到达的。注意,禧运楼所在的位置 (1, 1) 也被认为是可以到达的。
分析:根据样例,我们在场上就想到了正解的一部分,就是维护每一行以及每一列可以到达的最远位置,然后想加,但是很快就可以hack掉自己,hack如下:
(×代表障碍,数字表示统计次数)
× | ||||||
× | × | |||||
× | ||||||
× | ||||||
× | ||||||
那么我们可以到达32个格子,但横行统计有8个统计不到,竖列则有6个统计不到,那么我们就要额外维护这些统计不到的格子(当然我的大佬同学们也研究出了容斥的方法,这个就是多维护一遍,不做重点)。使用树状数组即可。
正解:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 200005;
int n, m, k;
int xx, yy, a[N], b[N]; //a表示每行到达最远位置,b表示每列到达最远位置
int c[N]; //树状数组
vector<int> tmp[N];
void add(int x, int v){for (int i = x; i <= m; i += i & (-i))c[i] += v;
}
int query(int x){int res = 0;for (int i = x; i; i -= i & (-i))res += c[i];return res;
}
signed main(){freopen("motor.in", "r", stdin);freopen("motor.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> m >> k;for (int i = 1; i <= n; i++)a[i] = m + 1;for (int i = 1; i <= m; i++)b[i] = n + 1;for (int i = 1; i <= k; i++){cin >> xx >> yy;a[xx] = min(a[xx], yy);b[yy] = min(b[yy], xx);}int ans = 0;for (int i = 1; i < b[1]; i++)ans += a[i] - 1;for (int i = 1; i < a[1]; i++){ans += max(0ll, b[i] - b[1]);tmp[min(b[1] - 1, b[i] - 1)].push_back(i);}for (int i = 1; i < b[1]; i++){add(a[i], 1);for (auto v : tmp[i])ans += query(v);}cout << ans;
}
好了,我要去学树状数组的扩展应用了,886!