CF204 Div 1 题解

成红名了~感谢p神~~


A:

题意:有2n个实数,选出n个上取整,剩下的n个下取整,求操作后所有数之和与操作前所有数之和的差的绝对值的最小值和。n<=2000。

解:先把所有数都上取整,剩下的就是选出n个数改成下取整。注意到如果选的数是整数,则对和没有任何影响;不然会使和-1。数一下有几个非整数然后一路减下来就好了。


B:

题意:有一个1~n的排列a,甲和乙轮流操作。甲会选择相邻的一对数满足a_i>a_{i+1},然后交换;乙也会选择相邻的一对数交换,有0.5的概率会选a_i>a_{i+1},有0.5的概率选a_i<a_{i+1}。a成为升序时结束。甲希望用尽量少的步数结束,求期望步数。n<=3000。

解:甲每次会令逆序对-1,乙则有0.5的概率令逆序对+1,也有0.5的概率令其-1。令ans_x表示逆序对为x时的最少步数,有ans_0=0,ans_1=1以及ans_x=2+0.5*ans_{x-2}+0.5*ans_x,即ans_x=4+ans_{x-2}。


C:

题意:构造一个长度为n*m的合法括号序列,每位被编号为0~n*m-1。第i位是左括号的代价是a_{i mod n},是右括号的代价是b_{i mod n}。求最小的代价。n<=20,m<=10^7。

解:当时我猜了一个结论:最优的序列一定是长度为2n的合法序列的循环,或者开头和结尾的n个括号拼起来是合法序列,中间则是长度为n或者2n的循环。……实际上就是下面的这个东西。

结论:括号的层数不会超过n。……不知道怎么证,官方题解也没写证明……那么可以用DP求,令f[i][j]表示i个括号,j层的最小代价。官方的做法是求出长度为n的括号序列的转移矩阵,然后矩阵快速幂……我的做法就是用我猜的那个结论分类讨论……反正都能过。

不过我实在觉得我的做法不科学……p神神吐槽:“他有数据在测吗……”


D:

题意:定义一次操作为,选出一个所有元素相同,而且下标构成等差序列的子序列,然后删掉这些元素并给剩下的元素重新标号,可以任意打乱剩下元素的顺序。给定长度为n的序列a,有q次询问,每次询问一个子串最少要进行几次操作才能全部删掉。n,q<=10^5。

解:做完了第一次操作之后可以直接把所有元素排序,然后操作次数就是不同元素的种类了。不同元素的种类是经典问题,那么关键就在于第一次操作能否完全去掉一种元素。我们可以用莫队算法,对每种元素维护一个双端队列(deque),在加入/删除时判断一下就好了……

而判断的方法是,先预处理一个并查集。枚举所有权值,记这些数的下标为x[1..k]。如果x[i]-x[i-1]=x[i-1]-x[i-2],那么就把x[i]和x[i-1]在并查集中合并。如果deque中只有0个或1个元素显然成等差序列,否则找到deque中队首第二个元素和队尾的元素,判断它们在并查集中是否在同一块内,在则为等差序列。


E:

题意:给定一个长度为n的序列,可以将任意一些元素置成相反数。求序列最少的逆序对数。n<=3000。

解:rng_58:"Why is E E?"

官方给出的做法是某种神DP……实际上根本没有那么复杂。

我们先把所有数取绝对值。考虑一对数a_i和a_j。考虑其大小关系,以及两个数是取正还是取负,一共8种情况。乍一看好像要网络流?其实没那么麻烦……

我们观察到,一对数会不会成为逆序对,其实只和较大数的正负有关。那么考虑每个数成为较大数的数对个数,即其前面和后面比它小的数的个数。其前面比它小的数没有成为逆序对,而后面的成为了逆序对。取负之后,前面的会成为逆序对,而后面的不会。那么比较哪边的数更多来决定是否取负即可。

剩下的问题似乎在于相同的数的处理。其实不用处理的,因为从左到右前面比它小的数必然会越来越多,而后面比它小的数必然越来越少,所以一定是前若干个数取负,也就不存在逆序对。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值