CF上分日记

1621B-1500分
大意:给一堆区间,每个区间有标价。某人要买一个或两个区间,要求这些区间中包含的数的最小值和最大值差距尽量大,在此基础上花费尽量少。求这个花费。
钻进了非要在线处理的牛角尖,不知道该怎么维护最优的选择,因为存在选择一个长区间和两个短区间的交替。
其实,用离线的眼光来看,我们在拿到所有区间后,想要得到答案,只需维护三个东西:
1,左端最小的区间的花费,以及这个左端值
2,右端最大的区间的花费,以及这个右端值
3,区间长度最大的区间的花费,以及这个长度
注意,3中区间也会被收入1或2中。
在线到最后,只有区间长度最大的区间才会对两个最左最右的短区间产生挑战。如果这个最长区间长度比左端值右端值的差还小,那就不需要考虑。如果相等,则判断其花费与1、2中区间花费和,如果小于,就选择3;否则就是1+2。

1614C-1500分
有一个序列,序列中有n个数。我们列出它的所有子序列,则子序列个数为N=2n。对每个子序列中的元素按位异或,然后将这N个异或值相加,得到和。求这个和ans?

将序列中的所有元素分为Aset和Bset。Aset中的元素第i位全是0,Bset中元素第i位全是1。从A中选取数个元素组成数列a求异或,从B中选取数个元素组成数列b求异或,再将求得的这两个值异或;列举所有可能的a、b组合求得异或,再求它们的加和,即可以得到ans的第i位的bit和。这个和怎么求?由于当a、b异或为0时对ans第i位没有贡献,所以不用考虑这样的情况,只需找a、b异或为1的组合个数。
由于无论怎样从A中选元素组成a,其异或都是0,那么所有a都可以选择,个数为2|A|;这样一来b必须异或为1。这只需要让b中元素个数为奇数个。这样的b的个数为 C1|B| + C3|B| + … + C|B|-k|B| = 2|B|−1 种,其中当 |B| 为偶数时,k = 1,奇数时,k = 0。
所以a、b异或为1的组合个数为C12|A| *C12|B|−1 =2|A|*2|B|−1 =2n−1
注意2n−1 仅仅是ans第i位的情况。而且,如果所有元素第i为都为0,那么Bset中没有元素,不存在异或为1的a、b组合,所以最终答案中第i位异或和是为0的;只有当至少一个元素i位为1,Bset才有元素可以挑出来,得到2n−1 的答案。恰好题目中给了序列所有元素的按位或值,只要存在元素的i位为1,则这个按位或值的i位就一定为1。(好吧,题目给的是序列的子串的按位或值,把它们再按位或一下就好,等价的)把这个值与2n−1 相乘即得答案。
Then the solution to this problem turns out to be very simple: let x be equal to the bitwise OR of all elements of the sequence (or, the same thing, bitwise OR of all given segments).

1618E-1700
题目大意是,n个艺人各自有不同的表演时长,记为数组a。他们每个人都各自住在一个城市i,要以时钟顺序i->n->1->i-1,从自己城市出发,去每个城市表演一次。每次表演,时长增加a[i]。最终,记每个城市所有艺人的总表演时长为数组b。给出n、b,求一个可能的a。
题中n、b的元素均为大于1的整数,要求求得的a也为大于1的整数。
这题就是列出:
suma=sumb/[n*(n+1)/2]、

要耐心地完整写出bi公式。然后再耐心地写出bi+1的公式。很自然地,让邻项bi+1、bi相减,消掉各项ax的系数,最终得到ai+1的表达式。沉住气。
在过程中,suma、ai如果出现小数或小于1,则说明无解。判断一个数是否是小数,只需在除法操作前,看分子模分母是否为0,否则相除后一定为小数。不要图省事判断a-(int)a是否为0,因为double转Int会四舍五入,不等也可能变相等。

1619E-1700
题目大意:给n个整型数,都大于等于0且不大于n,每次操作可以选任意一个数加1。设i依次等于0到n,求使得i为这组数的MEX值所需要的最少操作次数。MEX值:一组数中没出现过的值中的最小值。比如,[1,2,4,5]的MEX值为3。
解法:对每个i,使其为MEX,需要处理的事有两件。第一件是观察数组中是否存在0~i,有哪个不存在,则挑一个比它小的数增加。注意这个数至少有两个,否则西墙补了东墙没了。第二件是,找到数组中等于i的所有数,都加1,这样使得i不存在于数组中。

i-1对第一件事处理过后,就保证了0~i-2都存在于数组,于是i只需看i-1是否存在于数组。如果不存在,则需要找到一个<i-1的个数多于1的最大值,让它变成i-1。
为了实现这个,我们可以维护一个Stack。这个Stack存比i-1小的所有数,不在乎重不重复,因为有几个存几个。当需要找到比i-1小的数时,pop一下,算下与i-1的差值加到sum上。如果stack空了不能pop,那么从这个i到n-1的所有答案都是-1,即无解。
每次i的两件事处理完后,更新stack,while(cnt[i-1]>1)i-1一个一个push进去且cnt[i-1]–。
这样,每次i需要比i-1小的数时,在栈顶的一定是满足条件的最大数。

全程不需维护stack中值的个数,或是原数组a。

sum值记录第一件事的开销,是随着i增加而累加的。每个i输出的ans应是sum+cnt[i]。cnt[i]是i在第二件事上的开销。

1619D-1800
题意:n个人,m家商店。每家商店分别为n个人提供一个礼物,这些人对自己的礼物有一个满意值。要求挑选最多n-1家商店,为n个人每人买一个礼物。有一个人的满意程度会是所有人中最小的。求这个最小满意度在所有挑选情况中的最大值。
思路:最小值的最大值 ==> 二分搜索。设这个最小值的最大值为x。x的下界是1,成倍地增长,每增长一次,check一下x是否true。找到第一个为false的x,则二分搜索范围(即最终答案范围)确定为1~x。其实是x/2到x,但是二分一下就能缩小到这个范围所以不用管。到二分循环里,依照原样check,直到找到check为true的最大值,就是最终答案。
重点在于,怎样写check(x)?即怎样才能知道存在这样一种商店选择方式,使得每个人的满意程度都大于等于x?条件为有n个人,至多选择n-1家商店——则解必然有效的最宽松的前提为,n个人,选择n-1家商店。为满足这个最宽松的条件,意味着必须要有两个人的礼物能够从同一家商店买,并且余下的n-2个人都能从不管哪家商店里买到礼物。
因此check为true总结为两个条件:1.存在一家商店可以同时满足两个人的礼物满意度大于等于x。2.满足1的前提下,所有人都可以在不论哪家商店找到一个满意度大于等于x的礼物。
这与商店个数m>n-1、=n-1、<n-1都是无关的。我们只需关心n个鸽子如何在小于等于n-1个笼子里摆放的问题。是的,鸽笼原理,只要将两只鸽子关进同一个笼子,那么其余n-2只鸽子不论怎样摆放,它们占用的笼子总数都不会超过n-1个;同时,如果关起n只鸽子占用不超过n-1个笼子,则必定有至少两只鸽子是关在一起的。充分性必要性都有了。

1617D1-1800
题意:交互题。给1~n个数,n为3的倍数。其中有k个坏数,且n/3<k<2n/3。每次可以询问某几个数中是坏数多于好数还是好数多于坏数,如果坏数多,机器回答0,反之回答0。要求在2n次询问以内给出答案:坏数的个数和具体数。
解:
首先,如果我们能找出这些数中的其中一个坏数和其中一个好数,那么拿着这两个数对余下n-2个数询问n-2次,就可以得到所有数的好坏属性。例如,已知1好2坏,那么询问1、2、3中好数多还是坏数多,如果是好数多,则3必为好数;反之则3必为坏数。同理1、2、4,1、2、5…
那么,怎样确定出一个好数和一个坏数?如果固定数字个数地、一个一个向前叠着推进询问n次(比如,两次询问分别为:1、2、3,2、3、4),并且给出的回答是相反的,那么就说明1和4的属性是相反的,且可以根据回答分别确定他们的好坏性。但是怎样确定一次询问的数字个数,才能保证n次询问中至少有两次相邻询问的答案是相反的?
来关注k的范围。非常tricky,它意味着,如果我们每次询问三个数,一定至少有两个相邻询问答案相反。因为,假设回答全为1,则每组的三个数中的坏数至多有1个,而这只能使坏数的个数最多=n/3,与题设矛盾。因此回答不可能全为1。同理回答不可能全为0,否则好数个数至多=n/3,即坏数不可能小于2n/3,与题设矛盾。这样一轮询问(n次)内必然有答案从0变到1或相反的时候。由此可以确定一个好数和一个坏数。再执行题解开始说的办法,即得解。

1625C-1700
题意:一条公路上,从起点到终点之间,有一些牌子。记牌子i上的数字为x。从牌子i到牌子i+1之间的这段路,只能按照每单位长度用时x秒通过。规定起点上一定有一个牌子,且这个牌子不能去除。要求在去掉k个以内牌子的前提下,求从起点到终点的最小通过时长。
题解:dp。
第一步:n=100,猜测可能是三层dp。
令dp[i][j]为:前i-1个牌子(第i个牌子保留)中去掉j个,从起点到第i个牌子的位置所能达到的最小用时。那么最终答案应该是dp[n+1][0~k]中的最小值。
怎样在dp[i][j]二层循环基础上找到第三层循环?我们可以从顶部开始思考。即达到终点的那一步:dp[n+1][0~k(记为j)]。到达终点的最后一段路,一定是从所有牌子中的其中一个开始,按照它的速度前进直到终点。为此我们需要从所有牌子中列举这个牌子。记这个牌子为f,则f到终点之间的所有牌子都要去除,假设要去除的牌子个数为q,且目前二层循环的去掉牌子的总个数为j。那么,从f直达终点的最佳用时,表示为从起点到f去掉(j-q)个牌子的最佳用时 + f直达终点的用时。在第三层循环中列举所有f,最小的那个即为答案。
推而广之,我们找到了
状态转移公式:dp[i][j]=min{dp[i][j],dp[f][j-(i-f)+1]+a[f] * (d[i]-d[f])}
i、j、f边界限制:2<=i<=n+1 , 0<=j<=i-2 &<=k, i-j-1<=f<=i-1
初始化:dp=INF,dp[1][0]=0;
搞清楚的事:边界限制,根据事实写出来就可以。关键在于初始化要全面。哪些需要初始化?在子结构中不曾照顾到的边缘。比如,我们的dp[i][j]意义是从起点到第i个牌子去掉j个的最小用时。但如果i=1时,需要行驶的路途为0,此时根据常识,dp[1][0]用时一定是0。初始化完成。不需要再考虑要不要初始化dp[2][j],因为这在我们的子结构中是有意义的。
误入歧途:以为两层循环就可以找到最佳dp[i][j]。即,dp[i][j]=Min{dp[i-1][j]+a[i-1]*(d[i]-d[i-1]) , dp[i-1][j-1]+a[trace[i-1][j-1]] * (d[i]-d[i-1])}。反例:
4 100 2
1 2 7 8
1 2 3 100

1633D-1600
题意:把1按规则变到指定的数值,需要几步那么代价就为几,同时会给予这个值相应的奖励。给一堆指定数字序列b[]及其奖励c[],限定最大总代价,求不超过这个代价的前提下,能得到的最大总奖励。变化的规则是,bi=bi+下界(ai/x)。这算一步。i和x自己选定。ai、x都为整型。
题解:时空优化的0-1背包、bfs。先用bfs把数列中的数所需代价计算出来,然后,使用0-1背包解决即可。
bfs:首先建图,把1~1000的每个数与其通过一步操作能够到达的数建立边。比如,对于5,它能到达的有10=5+下界(5/1),7=5+下界(5/2),6=5+下界(5/3或4或5),以及5。那么5到10、7、6、5有边。建立完毕后,从1开始bfs,计算从1到1000内每一个数所需的最小步数。
时空优化的0-1背包:空间上,由于无法建立1e3 * 1e6的数组dp[][] ,因此需要有一个滚动数组的优化。这里注意了,0-1背包的dp[][]一维应为前几个物品个数,二维应为背包容量。此时才方便优化为滚动数组。否则很麻烦。时间上,1e3 * 1e6的复杂度有点大,会T。其实,从1变化到1000内的任一个数,最多只需12的代价。这个12可以通过找bfs得到的代价数组中的最大值确定。那么,如果有n个数,背包容量最大n12就够了,不需要1e6。因此让k=min(k,n12)就行。这样时间复杂度缩小至1e7左右。
关于背包问题的空间优化,详见博文here

1637D-1800
在这里插入图片描述
这题问题就出在没有把数学式化简充分。
2a1a2+2a1a3+a1a4+2a2a3+2a2a4+2a3a4=a1a2+a2a1+a1a3+a3a1+a1a4+a4a1+a2a3+a3a2+a2a4+a4a2+a3a4+a4a3,这种式子,是a1~a4完全等价的式子。假设Σa=s,则该式可以进一步化简为Σai*(s-ai)。后续化简见下图。
在这里插入图片描述后来在写dp时还有一个小细节:
在这里插入图片描述
这样写会出问题。本来在某一个j值时,dp[i][j]为1,那么加上a[i+1]后的dp被置为1。但是当j变换时,如果这个后来的dp[i][j]值为0,恰好这个j加上b[i+1]后等于之前的j+a[i+1],则这个dp值又被错误覆盖为0。所以要写上注释中的两个If。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值