刷题记录:Codeforces Round #724 (Div. 2)

Codeforces Round #724 (Div. 2)

20210713。网址:https://codeforces.com/contest/1536。

div2明显比div3难多了啊…只做了前4题,然后看了看第五题的题解。第五题给我一种……比较难想的感觉。

可能以后还是会做div3,或者只做div2的前几题。感觉div2的题目可能并不是我这个水平应该写的……下一步也可能会根据难度分类找题刷。还有就是学DL,喊了一周半,什么都没看,接下来要看了……我会继续加油的。

我会继续加油的。

A

定义nice数组:对于任意两个不同的元素,他们差的绝对值都会出现在数组里。

给我们n个整数(n最多100,每个数都在[-100,100],顺序无所谓),用这n个整数构造一个长度不超过300的nice数组。如果能构造出来,就输出这个nice数组的长度k和数组的内容。

如果给我们的n个整数里面有负数,那么拿一个正数i去与负数做差,差的绝对值比i大,这个【差的绝对值】应该也在nice数组里。然后把【差的绝对值】再与负数做差……越做差越大,肯定不能构造出nice数组的。

看到样例里有一个输出是这样的:2 4 6 8 10 12,看起来像等差数列的形式,这inspire了我接下来的想法:如果给我们的n个整数里面没有负数,我们可以这样构造:从0到【n个数的max】,把这n+1个数作为nice数组。公差为1,这是最简单的等差数列了。

当时提交的时候忘了【给我们的n个数中包含0】的情况,构造的是1-n,然后wa了一次。

其实,可以更简单:原来提交数组0-n,但是n最大是100,省事起见不如直接提交0-100。也就是说,如果给我们的n个数中没有负数,就提交0-100,否则构造不出来nice数组。

B

定义一个字符串的MEX:这个东西是【不作为原字符串的连续子串】的最短的字符串。啊,空字符串不能算MEX。如果有多个这样的字符串一样长,那就选按字典序最小的那一个。

举个例子,abcdefg的MEX:h。不在串内的第一个(按字母表排)字符就是MEX。

如果所有字符都在串内出现呢?比如abcde…xyz,它的MEX是aa。

题目给我们一个长度不超过1000的字符串,让我们找它的MEX。时间限制是2s。

考虑暴力枚举的做法:

MEX为单字符串的情况:a-z都在串内吗?

MEX长度为2的情况:aa-zz,一共有26*26=676种情况,全枚举一遍时间也可以接受。

MEX长度为3的情况:aaa-zzz,一共有26³=17576种情况。假设MEX长度>3,那么这17576种情况都要出现在串内,每一种情况的出现至少要贡献一个新字符吧,所以这个串的长度肯定一万多了。然而字符串长度最多才1000,因此MEX长度撑死就是3了。所以枚举到3就可以了。

在枚举的时候,可以用STL string自带的方法判断子串是否存在。

C

给我们一个长度最多5e5的、由D和K组成的字符串。然后我们对它的每一个前缀字符串,求【分割的数目】。

分割的数目:通过切ans-1刀把数组切成ans段,ans-1可以=0也就是一刀都不切。要求分割后的每一段【D数目和K数目的比值】都相同。比如说,D数目:K数目=4:2和2:1比值是相同的,3:0和1:0比值是相同的。ans就是分割的数目。

对每一个前缀字符串,我们都要求一个分割的数目。可以想到,每一个分割的比值都等于整个前缀字符串的比值。如果大字符串和它的某一个小前缀字符串的比值是一样的,那么就可以从这个【小前缀字符串】的末尾切一刀。

感觉自己已经语无伦次了……总之解法就是,考察这个前缀字符串前面的前缀字符串中,有多少个串和本前缀串的比值是一样的,本前缀串的分割数就是【比值相等数目】+1。如果前面没有串和本串比值相等,则分割数=1。

比值的记录:如果直接用double记录D数目/K数目,K数目可能为0,不如用D数目/(D+K数目),即D数目/串长度。其实,如果直接用double(STL map<double,int>),可能会因为浮点误差wa掉,(好像评测机的设置专门把这种做法卡了,样例都过不了,而本地是可以过样例的)。所以最终的做法是记录一个pair<int,int>,记录【D数目和串长度】约分到互质的结果。然后要注意,写gcd时要特判【D数目=0】的情况,不然会出现除0错误。

D

定义omk数组:对于数组\(a_1\)\(a_{2k-1}\),omk数组记为\(b_1\)\(b_k\),其中\(b_i\)是数组\(a_1\)\(a_{2i-1}\)的中位数。给我们一个数组b,问它是否是一个omk数组,就是是否能构造出a。

自己想,越想越乱还做不出来,就去看题解了……

题解的做法:

假设数组\(b_1\)\(b_k\)是omk数组,现在我们看\(b_{k+1}\)。如果\(b_1\)\(b_{k+1}\)是omk数组,可以用原\(a_1\)\(a_{2k-1}\)数组构造一个\(a_1\)\(a_{2k+1}\)数组(也就是再插入两个数),使得\(b_{k+1}\)是中位数。

在排好序的数组\(a_1\)\(a_{2k-1}\)中,(因为\(b_k\)是中位数嘛),\(a_k=b_k\)。只有\(a_{k-1}<b_{k+1}<a_{k+1}\)\(b_{k+1}\)才能插入,否则\(b_{k+1}\)做不了中位数。

然后,\(a_{k-1}\)肯定不能比b数组中【小于\(b_k\)的元素中最大的\(b_i\)】更小,\(a_{k+1}\)肯定不能比b数组中【大于\(b_k\)的元素中最小的\(b_j\)】更大,因为b数组的每个元素都在a里呀。

这样就用原来的\(b_1\)\(b_k\)数组限定了\(b_{k+1}\)的范围。如果没法找到\(b_i\)\(b_j\)\(b_{k+1}\)的范围就没有界限。这是【\(b_1\)\(b_{k+1}\)是omk数组】的必要条件。

题解证明它也是充分的。只要满足这个条件,我们就能这样构造a数组:

  • 第一个元素,\(a_1=b_1\)
  • 如果\(b_{k+1}=b_k\),往数组里塞一个正无穷一个负无穷。
  • 如果\(b_{k+1}<b_k\),往\(a_{k-1}\)\(b_k\)中塞一个\(b_{k+1}\),再塞一个负无穷,这样可以保证\(b_{k+1}\)是中位数。
  • 如果\(b_{k+1}>b_k\),往\(b_k\)\(a_{k+1}\)中塞一个\(b_{k+1}\),再塞一个正无穷。
  • (题解中说,如果\(b_{k+1}\)和以前的某个\(b_m\)相等,我们就插入两个负无穷/正无穷,让那个\(b_m\)重新变成中位数。

所以,我们使用STL set(set会自动把元素排序),对于每一个\(b_{k+1}\)考察那个条件。如果一直满足下去,a就是omk数组。

posted @ 2021-07-13 18:34  MoonOut  阅读(60)  评论(0编辑  收藏  举报