刷题记录: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数组。