2025-11-22 提高组校内模拟赛 div 1
T1
一个贪心题(考场上没切出来,悲)(一下把点对叫成区间)
考虑每次我们应该选最小的代价合并,这是显然的。那么现在最大的问题时我们因该如何找到最小的区间,一种思路是我们考虑枚举,然后删除,这是\(N^2\)的显然过不了,思考瓶颈是什么,发现是无法动态维护出最小区间,考虑用线段树,记录每个点的位置,如果删掉一个点,那么它后面的点的位置-1,这是一个区间修改,然后我们再查找最小的同颜色区间。但是,我们发现如果这样修改完再查找,找的时候一次是nlogn的,显然挂了
那我们改换思路,继续思考瓶颈,为什么要用线段树,因为要动态维护出最小区间,有什么数据结构可以支持吗,似乎没有,并且出题人一般也不会再T1放难的数据结构,继续找本质,为什么要动态,因为每次删除一个区间会改变其他区间大小,然后改变顺序。似乎到头了,我们考虑从这里入手,有办法不改变其他区间顺序吗,找找性质,发现似乎合法的删除两个点不改变删除其他点对的顺序!!!
证明:
1.如果两个区间是相离的,那么显然不会互相影响
2.如果两个区间是相交,那么删除任意一个是可以
3.如果有包含关系,那么需要先删里面的区间
那么我们删除一个区间对与他相离,相交的没有影响,所以这些区间先后顺序无所谓,对于情况三因为我们是合法删除,会先删小的,那么默认满足这个条件
所以,合法的删除两个点不改变删除其他点对的顺序
证毕
发现有这个结论后,我们就不需要线段树的区间查询了,那么显然是可以用线段树解决
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N_ 500005 * 2
#define M_
#define P pair<ll, ll>
void read(ll& x) {
char ch = getchar();
ll f = 1;
x = 0;
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - 48;
ch = getchar();
}
x = x * f;
}
const ll inf = 1e9;
struct node {
ll l, r;
} t[N_];
ll n, a[N_], cnt[N_], ans, f[N_];
void add(ll x, ll val) {
for (; x <= 2 * n; x += x & -x) f[x] += val;
}
ll ask(ll x) {
ll res = 0;
for (; x > 0; x -= x & -x) res += f[x];
return res;
}
int main() {
freopen("happy.in", "r", stdin);
freopen("happy.out", "w", stdout);
read(n);
for (int i = 1; i <= 2 * n; i++) read(a[i]);
for (int i = 1; i <= 2 * n; i++) {
cnt[a[i]]++;
if (cnt[a[i]] == 1)
t[a[i]].l = i;
else
t[a[i]].r = i;
}
sort(t + 1, t + 1 + n, [](node x, node y) { return x.r - x.l < y.r - y.l; });
for (int i = 1; i <= n; i++) {
ans += (t[i].r - t[i].l + (ask(t[i].r) - ask(t[i].l)));
// cout<<t[i].l<<" "<<t[i].r<<" "<<ask(t[i].r)<<" "<<ask(t[i].l)<<endl;
// cout<<ans<<endl;
add(t[i].r, -1);
add(t[i].l, -1);
}
cout << ans;
return 0;
}
小结:考场上要勇于改换思路,无思路可以从1.出题人角度 2.多问为什么,从瓶颈出发 3.从题目中找性质解决卡点
T2
首先,opt1是好做的,直接用map维护一下就好,opt3用map查询一下即可,然后你就会有4pts
考虑难维护的2,本质是把一个连通块变成一个完全图,但是我们不能真的两两连边,一个直观的思路是我们打标记,但是我们不可能对连通块内每个点都打上标记,这时容易想到我们可以对于连通块打标记,但是我们发现对于每次操作一,连通块的大小都有改变,这时标记就不可用了,那么我们可以把每次操作2存下来,然后对于每次1,我们攒起来做。
但,这只能优化一小部分,还是可以被卡掉,我们考虑瓶颈是什么,我们无法使得标记一直有效,那么一个思路是我们可以把标记和连通块分开来存,注意到题目提醒我们用并查集,那么我们尝试用并查集维护标记(即维护是否在一个完全图内),对于操作2,我们还需要连通块的信息,那么再用一个并查集维护连通块,那么这个似乎很好做。
考虑操作2,我们对于x所在连通块里的所有完全图,都给它扔到x的完全图并查集下面,表示合并成一个大的完全图,对于每个连通块我们存一个vector,记录连通块内的所有完全图。这时我们发现似乎可做,但是复杂度还是太高,瓶颈在哪,在于每次合并连通块,对于里面的所有完全图我们要合并起来,合并优化?启发式合并。这样每个完全图只会合并一次。对于操作3,直接map查+判断是否在同一个完全图内
你先别急
小结:合并问题->启发式合并 ,要善于从题目中找信息
T3
你先别急
T4
你先别急
总结:
1.考试策略还可以,但T3,T4暴力打太久,需要适当压缩。
2.多找性质,充分利用题目,认真程度还可以,多思考瓶颈,一些思路切入角度要熟练并常加练习。
3.打代码速度要提高。
4.贪心,dp,字符串,扫描线题多做。

浙公网安备 33010602011771号