CF div3 995 (A~G)

期末周之第三把网瘾(真是越来越放肆了...)。这次赛时了一把div 3 , 又一次只做出了A~E,写完E后剩下的题没时间看了(受了些寝室噪音的干扰,最后二十分钟才出)。赛后看了下F和G,感觉也是一时半会儿做不出来的题,遂来补题。

ABCD

这次前四题都很白给。ABC纯模拟题,D是枚举左端点二分右端点的典套路。

不过BC的总共5发罚时确实有点说不过去了,这个和当时寝室比较吵,注意力不集中的关系比较大。以后在寝室打CF时应该提高一下专注力了。

E

用了树状数组 + 离散化过的。感觉这道题挺不错的,需要一点点的思维和代码实现能力。

题意就是给定n个区间[ai,bi] ,然后有一个单价w。对于某个区间,当bi>=w时,这个区间会被选,否则不会选;同时当w<ai时,这个区间会收到一个差评(在题目中区间是一个商品。这里为了简化题意,就直接这样陈述了)。让你钦定一个w,使得最后获得的总价值最大,并且差评数不超过定值k

首先有一个很关键的性质:钦定的单价w一定是题中给定的某一个aibi。证明很简单:将所有aibi放在一起排个序。反证一下,如果w不是其中的某个数,则:

  1. 当这个数不超过其中的最大值时,一定可以把他扩大到比它大的且最接近于它的数。这样差评数和购买商品的数量都不会发生变化,合法性仍然保持的同时单价提高了,答案也会变得更优。
  2. 当这个数超过了其中的最大值时,显然没有商品会被购买,总价值为0

故可以O(n)枚举单价w,答案一定在这些情况中的某一个。枚举时计算出当前情况下 购买的商品数 以及 收到的差评数 即可。

我赛时的思路是分别枚举aibi,两种枚举分别用不同的方式来判断。

枚举bi的判断方式:

将所有区间根据bi降序排序,这样在枚举时(设当前枚举到的区间为[ai,bi]w为当前枚举区间的bi),所有买的物品一定是当前枚举物品的前缀,不买的物品一定是后缀。维护当前的前缀中所有<wai的数量,这相当于带修的查找<k的所有数的数量,很明显是树状数组可以完成的事情。所以先将所有ai离散化,并在枚举的过程中修改并查询即可。

枚举ai的判断方式:

和上面的比较类似。将所有区间根据ai升序排序,这样在枚举时(设当前枚举到的区间为[ai,bi]w为当前枚举区间的ai),后缀的区间都可以被购买且不会收到差评(ai<bi);而前缀中,只要被购买的区间就一定会收到差评,但不是所有区间都会被购买。这样,就只需要在枚举ai的过程中,维护前缀中所有<wbi的数量,这些区间都不会被购买。这样,剩下的i1notbuy个区间都会被购买且受到差评。结合后缀信息,总的差评数和购买数就均已知了。

总复杂度O(nlogn),常数应该比较大,但肯定可以过去。

code

F

模拟 + 分类讨论,赛后看b站讲解后过的。

直接 在脑海中构想 or 画图,容易发现Joker出现的位置会形成若干段连续的区间。具体来说:

  1. 当移动的牌不是Joker可能出现的位置时,Joker出现的位置一定是中间的一段连续区间。
  2. 第一次移动可能是Joker的牌时,牌的前缀与后缀会出现Joker。
  3. Joker出现的位置最多只会形成前缀,中间,后缀三段区间,证明不再赘述。

所以只需要维护三段区间的左右端点即可。前缀和后缀可以分别用abovebelow单独的指针来维护,中间的区间用Lmid,Rmid两个指针来维护。模拟所有移动的情况,维护这四个指针的位置即可。注意区间相交时要把区间合并起来。

同时有一个坑点:第一次移动Joker时,若中间区间的长度为1,即只有一个Joker时,中间的区间会消失,即只会形成前缀和后缀两段区间,这个需要专门特判一下。当时自己在想这道题时除了这个坑点,其他的都没问题。还是得再细心一些。。。

code

G

状压dp。听完题解给的状态定义后,自己把 状态转移 和 预处理转移数组的方法 补出来了,也算是补得比较成功。

n<=20,毫不犹豫直接状压。

状态定义:dp[state][i]表示地图中只有二进制数state表示的全部蛇,并且最后一只蛇的编号为 i 时,在满足题述移动方式合法性的前提下,最右侧位置最近的格子是第几个。

状态转移:

dp[state|(1<<j)][j + 1] = min(dp[state|(1<<j)][j + 1] , dp[state][i + 1] + g[i + 1][j + 1]);

其中编号为 i 的蛇在已知序列中的最后一个,编号为 j 的蛇要加入到当前末尾后面的位置。

g[i][j]表示当 编号为 i 的蛇 和 编号为 j 的蛇 紧邻时,为了保证所有移动操作的合法性,二者需要间隔的最短距离。这个需要根据题目给定的移动序列预处理出来。

预处理g[i][j]的方法:

首先每只蛇在未经移动操作时至少间隔1个格,故初始化为1。

之后的 + 号处理类似于栈的操作:所有的减号可以抵消掉它后面和它相关的加号。具体解释可能比较麻烦,可以看代码和注释来感性理解一下,还是比较好懂的。

哦对了,最后的答案应当取下式的最小值,而不只是dp数组的最小值:

dp[(1<<n)-1][i] + move_front[i] , 1 <= i <= n

其中movefront[i]表示第 i 条蛇向右移动的距离,即移动操作 i+ 出现的次数。

code

posted @   jxs123  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验
点击右上角即可分享
微信分享提示
主题色彩