NOIP 2010提高组题解

在这里插入图片描述
这是同机房一位巨佬在AK IOI之后发表的感言。

为了学习他的这种精神(我太菜了,但我也想像他一样AK IOI QAQ),这篇题解就诞生了。

战车被马拉着

Solution

T1

直接模拟。注意入队的时候打上标记,出队的时候清楚标记,每次查询的时候直接 O ( 1 ) O(1) O(1)查询标记即可。

时间复杂度 O ( N ) O(N) O(N)

T2

一直在那里想二分,结果云云出来一个 O ( log ⁡ 1 0 9 n 2 ) O(\log{10^9}n^2) O(log109n2)的解法(剪枝一下跑不满)……我太菜了……

我们考虑贪心。记 u , v , w u,v,w u,v,w为一条无向边,表示 u u u这个罪犯与 v v v这个罪犯之间的冲突值为 w w w。按 w w w从大到小排序之后,我们从前往后扫描一遍,尽量让当前这两个罪犯被安排在两个不同的监狱。如果已无法避免(比如之前已经决定了 1 1 1 2 2 2, 2 2 2 3 3 3这两对罪犯分别在不同的监狱,那么我们就无法避免 1 1 1 3 3 3在相同的监狱)就直接输出当前的 w w w。这个可以使用扩展域并查集完成。

最后,注意如果可以避免所有的冲突应该输出 0 0 0

时间复杂度为 O ( N l o g N + M l o g M ) O(NlogN+MlogM) O(NlogN+MlogM)

T3

很裸的 d p dp dp

状态设计: d p i , a , b , c , d dp_{i,a,b,c,d} dpi,a,b,c,d表示看到了第 i i i个位置,四种卡片分别用了 a , b , c , d a,b,c,d a,b,c,d张。

状态转移十分显然,略掉。


可以发现,状态过多,会 M L E MLE MLE T L E TLE TLE

现在,我们要 ⌊ \lfloor 用尽可能少的维度去描述一个状态的轮廓 ⌉ \rceil 。可以发现, a , b , c , d a,b,c,d a,b,c,d i i i之间有一个等量关系,即

1 + a + 2 b + 3 c + 4 d = i 1+a+2b+3c+4d=i 1+a+2b+3c+4d=i

于是,我们就可以随意省去一维,就做完了。

时间复杂度 O ( 4 0 3 N ) O(40^3 N) O(403N)

T4

下面的解法保证正确,但与官方题解甚至所有题解都有不同之处,完全原创!

首先,我们建图, u u u v v v连一条有向边当且仅当水可以用 u u u流到 v v v。可以发现,这是一个 D A G DAG DAG(什么?你说这里面会有环?你的意思是 3 > 2 > 1 > 3 3>2>1>3 3>2>1>3吗)。于是我们可以通过一遍拓扑排序来求出第一行上的每个节点分别可以到最后一行的哪些节点。

但是,仅仅到这里的复杂度就退化成了 O ( n m 2 ) O(nm^2) O(nm2)。怎么办呢?可以发现,我们问的是"能否到达",可以压缩为一个 01 01 01的状态。但是,最后一行有 500 500 500个位置你怎么压?我们套路地拆开这个二进制数,拆成 8 8 8个甚至 9 9 9个无符号整形量来转移,不就行了吗。时间复杂度是 O ( n m ) O(nm) O(nm)是不是很神奇

首先,特判一下“不能”的情况。如果第一行全部安排蓄水池都不行,那么就显然是“不能”的情况。只需要再用 int512 上面所说的拆开的方法,把第一行所有格子的状态给或一下,看看是否每一位都是 1 1 1即可。

接下来,怎么办呢?在NOIP 2010的考场上本蒟蒻就想到了这一步,后面就不会做了QAQ

可以发现,此时所有第一行格子能够到达的最后一行的位置,一定是一段连续的区间。对,一定是一段连续区间。这是一个无比重要的性质。

简要证明一下: 如果这不是一段连续的区间,假设空出来的是第 k k k个位置,那么显然第一行其他的所有位置都无法到达 k k k。那么这应该归为无解的情况,在有解的情况下是绝对不会出现的。

所以,现在我们将一个二进制的状态转换为一个区间 [ l , r ] [l,r] [l,r]。然后,我们相当于要选择尽可能少的区间去覆盖最后一行,这个就是一个裸的贪心——按左端点排序,左端点相同按右端点排序,直接从前往后扫一遍即可。即,我们每次在保证左端点小于等于之前选的右端点,无空格的情况下,让右端点延伸得最远,这是贪心的思想。

总时间复杂度 O ( n m ) O(nm) O(nm)。此题得到完美解决。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值