【2022暑假第一期】例题集锦

更好的阅读体验?

Day 1


性格公交车

每排有两个座位,所以只可能是一个内向的先坐下,然后一个外向的再坐下。同时,要考虑座位的宽度。

不难想到定义一个小根堆和一个大根堆,分别表示内向和外向的人可以坐的座位。开始时,所有座位的宽度放到小根堆里,每次内向的人就选顶部的座位。同时,把这个选择的座位放进大根堆里。这个座位就满足已经有一个内向的人。

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)


题海战

看到输入可能有重复,不难想到用 set 去重。每次用所有题目的全集在参加学生中筛选题目。对于比赛,只要学生的题目和目前的题目有重复,那就删掉它;对于训练,如果目前某一题目有人没有做过(即没有重复),就删掉它。

输出从小到大,而 set 内部有序,直接输出剩下的题目。

因为每次要不断删除题目,局部接近 log 级,时间复杂度为 Θ ( n k log ⁡ m ) \Theta(nk\log m) Θ(nklogm)(也许并不准确)。


Day 2


01背包第k优解

首先,第 k k k 优解必定由目前的前 k k k 优解转移过来。注意原先的转移方程: d p j = max ⁡ ( d p j , d p j − w i + v i ) dp_j=\max(dp_j,dp_{j-w_i}+v_i) dpj=max(dpj,dpjwi+vi)。不难想到用两个数组记录下 max 里的两个值。在原有的 d p dp dp 基础上再加一维,表示第几优解。

利用归并排序的思想,不断用两个数组的值更新前 k k k 优解。

时间复杂度 O ( n v k ) O(nvk) O(nvk)

for(int i = 1;i <= n; ++i)
	for(int v = V;v >= w[i]; --v) {
		int a[Maxn], b[Maxn];
		for(int j = 1;j <= k; ++j)
			a[j] = dp[v - w[i]][j] + c[i], b[j] = dp[v][j];
		int x = 1, y = 1, z = 1;
		a[k + 1] = b[k + 1] = -1; 
		while(z <= k and (a[x] != -1 or b[y] != -1)) {
			if(a[x] > b[y]) dp[v][z] = a[x++];
			else dp[v][z] = b[y++];
			if(dp[v][z] != dp[v][z - 1]) z ++;
		}
	}

Day 3


银河英雄传说

难点是求间隔的战舰。

分别记录每个点到根节点的距离,并查集的长度。

合并两个并查集 x x x y y y 时,可以对并查集的长度进行修改。将 y y y x x x 的距离更新为原来 x x x 的长度。

这样就有效处理了根节点,那每个子节点怎么更新呢?

只需要在查找的时候,顺带把子节点加上父节点到根的长度。


团伙

朋友之间不难求,但是敌人呢?

构造虚点,把敌人归在 [ n + 1 , 2 n ] [n+1,2n] [n+1,2n] 的编号中,这样敌人的敌人还是会在 [ 1 , n ] [1,n] [1,n] 中并与这个人属一个集合。统计时,还是只看 [ 1 , n ] [1,n] [1,n],忽略敌人。


格子游戏

封圈时,圈中的所有点都是连通的。只要加入这个两点的时候发现它们在同一个并查集中,就是封圈。

注意点的存储,为避免重复,把二维坐标转化成点 x ∗ n + y x * n + y xn+y


7.27测试


A

枚举起点,分别构造最小生成树。

把每个点连接的边权 d i d_i di 事先设成 v i v_i vi,在求解过程中再更新 d i d_i di

时间复杂度 O ( n 3 ) O(n^3) O(n3)

不难发现:建造一个发电站,就是一个自环,如何处理呢?对于每个点,都有一个自环。而且必须保证至少有一个点要走这个自环。不妨引入一个虚点 0 0 0,让每个点的自环都变成 0 0 0 i i i 的边。讨论正确性。

最小生成树是图中的一个联通块。因为必须有一个点与 0 0 0 连接,所以加上 0 0 0 之后,仍是连通的。

时间复杂度 O ( n 2 ) O(n^2) O(n2)


C

易得守卫有 n + m n+m n+m 个,思考怎么维护代价。

观察到 n , m , n m ≤ 1 0 5 n,m,nm\leq 10^5 n,m,nm105,正常的二维数组存储肯定会爆,想到图。

把它的横纵坐标分别作为起点和终点,为了避免点重复,将终点加上 n n n,这样就变成 i i i j + n j+n j+n 之间存在一条长度为 w i , j w_{i,j} wi,j 的边。

每一行 i i i 与某一列 j j j 相连,维护的是行。某一列 j j j 与某一行 i i i 相连且不重复,维护的是列。

这样最小生成树跑出来是 n + m − 1 n+m-1 n+m1 条边,而要使边数为 n + m n+m n+m,相当于要在树上再连一条边,形成基环树

求最小基环树即可,类似于 kruskal

时间复杂度 O ( n m log ⁡ ( n + m ) ) O(nm\log(n+m)) O(nmlog(n+m))

参考


D

一眼区间dp,对于每个 [ i , i ] [i,i] [i,i],可以确定 i i i 是否有球。同样,知道 [ i , j ] [i,j] [i,j] [ i + 1 , j ] [i + 1,j] [i+1,j] 也可以判定。

时间复杂度 O ( n 3 ) O(n^3) O(n3)

考虑优化。借助上面的思想,换一种角度:把每个 [ i , j ] [i,j] [i,j] 看作图中的一条边。由于存在有意义的自环 [ i , i ] [i,i] [i,i],为了不影响结果,只需要看作是 [ i − 1 , i ] [i-1,i] [i1,i] 即可。因此,存的 [ i , j ] [i,j] [i,j] 也要变成 [ i − 1 , j ] [i-1,j] [i1,j]。(可以理解为构造虚点)

要知道每个杯子的情况,即要使 [ i − 1 , i ] [i-1,i] [i1,i] 连通,也就是让整个图连通,又要花费最小,而花费又是边权,问题就转化成了求最小生成树

时间复杂度 O ( n 2 ) O(n^2) O(n2)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值