2025 牛客寒假 6 部分题解 (E, D, H, I)
本文首先发布于个人博客,博客园不定期更新,推荐去我的博客阅读。
I 小鸡的排列构造的 checker
看题第一反应是主席树。
定义 表示值 出现的下标(因为是排列只会出现一次),则每次询问中要求的区间排名即为 上 左侧在 之间的数的个数,加上 就是答案。使用扫描线——离线树状数组解决即可。(如果你没有学过二位数点,类比树状数组求逆序对即可)。
赛时代码:
int n, m;
cin >> n >> m;
vector<int> p(n + 1);
for (int &num : p | views::drop(1)) {
cin >> num;
}
struct Query {
int l, r, c, id;
};
vector<vector<Query>> queryByCVal(n + 1);
for (int i = 0; i < m; i++) {
Query query;
auto &[l, r, c, id] = query;
cin >> l >> r >> c;
id = i;
queryByCVal[p[c]].push_back(query);
}
vector<int> lst(n + 1);
for (int i = 1; i <= n; i++) {
lst[p[i]] = i;
}
Fenwick<int> tree(n);
vector<int> ans(m);
for (int val = 1; val <= n; val++) {
for (auto q : queryByCVal[val]) {
ans[q.id] = tree.GetSum(q.r) - tree.GetSum(q.l - 1) + q.l;
}
tree.Add(lst[val], +1);
}
for (int num : ans) {
cout << num << '\n';
}
H 小鸡的排列构造
我讨厌构造题...
猜测无论输入如何都存在满足条件的排列(即任意奇数或者偶数长度区间都是全错排),试着构造:
当 为奇数时: 的情况平凡,2 3 1
或者 3 1 2
。以前者为例,考虑以此构造 的情况,设第 4 位为 x
,由于后三位 3 1 x
必须满足全错排,因此只能是 2 3 1 1.5
的大小关系,即 3 4 1 2
。同理构造 的情况:3 4 1 2 0.5
即 4 5 2 3 1
,以此类推,不难看出规律 n-1,n,n-3,n-2,...
。(如果从 3 1 2
出发能得到另一组构造)。
不太清楚“对于一个任意长度为 3 的区间都是全错排的排列,任意长度为 5, 7, 9... 的区间也是全错排”怎么形式化的理解或证明,但是观察我们构造出的序列显然是满足的。
为偶数时同理,可以得到构造 n, n-1, n-2, n-3, ...
。
赛时代码:
int n, m;
cin >> n >> m;
int parity = 0;
for (int i = 1; i <= m; i++) {
int l, r, c;
cin >> l >> r >> c;
parity = (r - l + 1) & 1;
}
if (parity == 1) {
for (int i = n - 1; i >= 1; i -= 2) {
cout << i << ' ' << i + 1 << ' ';
}
if (n % 2 == 1) {
cout << 1;
}
cout << '\n';
}
else {
for (int i = n; i >= 1; i--) {
cout << i << ' ';
}
cout << '\n';
}
D Viva La Vida(Fried-Chicken's Version)
虽然题目是无向边,但是我们先将其看作有向边。画个简单的图,结论其实就一目了然:
(剩下的边用更大的数补全即可)
边权就类似势能一样,从高走向低,因此不能成环(重边除外)。由于出度为 1,所以每个联通分量一定有且仅有一个重边,所以数重边个数即可。
由于边权是排列,没有相等的数,也就是说对于一条重边,它的边权就是和这两个点相连的 条边里最小的一条,概率 。由期望的线性性,总期望就是每一条的期望之和, 即 。
代码略。
E 任造化落骰
参考官方题解的做法,先用单调栈预处理出 ,即 之后下一个改变 的位置,然后枚举左端点 ,用双指针处理 为 的二元对的个数,做个后缀和,每次询问二分找要的值就行。
代码:
int n, m, q;
cin >> n >> m >> q;
vector<int> a(n);
for (int &num : a) {
cin >> num;
}
auto calc = [&](const function<bool(int, int)> &cmp) {
stack<int> St;
vector<int> nxt(n);
for (int i = n - 1; i >= 0; i--) {
while (St.empty() == false && cmp(a[St.top()], a[i]) == false) {
St.pop();
}
if (St.empty()) {
nxt[i] = n;
}
else {
nxt[i] = St.top();
}
St.push(i);
}
return nxt;
};
auto nxtMin = calc(less());
auto nxtMax = calc(greater());
map<ll, ll> bkt;
for (int l = 0; l < n; l++) {
for (int i = l, j = l; i < n && j < n;) {
if (nxtMin[i] < nxtMax[j]) {
bkt[1ll * a[i] * a[j]] += nxtMin[i] - max(i, j);
i = nxtMin[i];
}
else {
bkt[1ll * a[i] * a[j]] += nxtMax[j] - max(i, j);
j = nxtMax[j];
}
}
}
vector<ll> vals;
vector<ll> sufSum;
for (auto [val, cnt] : bkt) {
vals.push_back(val);
sufSum.push_back(cnt);
}
for (int i = sufSum.size() - 2; i >= 0; i--) {
sufSum[i] += sufSum[i + 1];
}
while (q--) {
ll k;
cin >> k;
int ind = ranges::lower_bound(vals, k) - vals.begin();
cout << sufSum[ind] << '\n';
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~