CF div1+2 999 (A~F1)

赛时三题,D就差一个显然的剪枝就能过了,qwq...

A

显然第一步能选偶数就选偶数,之后只能选奇数。细节见代码。

code

B

对于选取的任意四条边,设腰为x,短边为a,长边为b,则能形成等腰梯形的充要条件为:x出现次数>=2,且a+2x>b。两个腰选最大,并且ab尽可能接近显然更优。具体实现见代码。

code

C

刚开这题时以为是一个神奇妙妙题,硬想了四十多分钟。等意识到是dp时,不到十分钟就码完了,只能说自己太唐了。。。

状态定义:dp[i][0/1]:表示考虑前i个人,且第i个人是诚实者(1)or说谎者(0)的方案数。

init:第一个人是诚实者的充要条件为a[1]==0,是说谎者的充要条件为a[2]==1(证明略)

ans=dp[n][0]+dp[n][1]

trans根据题目规定的条件,对每一步转移的合法性做相应判断,来决定是否转移即可,细节见代码。

code

D

逆向思考,b中每个数的拆分是唯一的。所以直接对b中的每个数尝试拆分。可以证明按任意顺序拆b数组中的数都是可行的,只要拆分过程中能与a中的某个数匹配则直接匹配,最后看是否能全部匹配即可。

注意,操作数最多为nm(本题赛时的败笔。太显然了,不知道赛时为啥忘了这一点。。)所以直接记录拆分次数,>nm时直接判不可行即可。同时,若拆分出的某个数没有在a中出现,且不能继续拆分(即为1),则也直接判不可行即可。

code

E

不难的一道题。

对某一个数的操作次数最多为m次,因为没有必要与相同的数,且最多能 and m个数。

故可以设一个数组w[i][j]a[i]操作j次,可以减少的最大差值。

该数组可以用O(n2m)的复杂度预处理出来,具体实现见代码。

再考虑k次操作:显然,每一次贪心地选择一个能最大化差值的方案总是最优的,而kO(nm)级别,故可以考虑模拟操作过程,每次贪心地选取最优方案。

暴力模拟的复杂度是O(nmk),考虑优化:

需要注意到一个关键性质:对于固定的iw[i][]的差分数组是递减的,即对于任意j1<j2

w[i][j1]w[i][j11]>w[i][j2]w[i][j21]

因为减少a[i]的方式是做与运算,故每次操作时,一定是贪心地选取能减少当前a[i]的最高二进制位为1的那个b[i],那么显然后续的操作,a[i]减少的值就一定不会比这一次操作多。也就是说随着操作进行,a[i]减少的值是递减的,故上式成立。

所以可以用一个大根堆来维护对于每个a[i]做当前操作会减少的差值,每次做完操作后把对a[i]做下一次操作会减少的差值放进堆中。这样可以保证每次堆顶都是最优操作(因为堆维护的都是当前操作,后续的操作 由上述证明可知 减少的差值都比当前操作要少,所以可以这样贪心,否则得用背包dp),模拟k次即可。复杂度为O(n2m+klogn)

code

F1

只需要注意到如下性质:

  1. 交换后的两个块会分别和其左右相同的数字粘在一起,不会再分开。
  2. 含有相同数字的任意块一定是保序的。

固定T,模拟S交换时的过程即可,尽可能让当前未匹配上的前缀匹配。详细见代码。

code

posted @   jxs123  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示
主题色彩