Codeforces Round #689 (Div. 2)
几乎所有题目都是思维题目,代码不长,如果想看请见提交记录
A. String Generation
题意略
比较简单的构造题目,直接"abcabcabc...."即可保证不会出现长度不超过\(k\)的回文串
B - Find the Spruce
统计矩形方阵中三角形的个数
原来单个的'*'也算在三角形以内了,太淦了
O(\(n^2 \cdot m\))
首先三角形一定都长一样,每一层的'*'分别是\(1,3,5......\),即可通过前缀和统计'*',然后暴力枚举每个顶点,就可\(O(n^2 \cdot m)\)
O(n^2)
在讨论区看到的神奇DP,思路比较巧妙
首先一个性质:除了一个'*'之外,其余的三角形至少是由该点下方的三个'*'构成
定义\(dp[i][j]\)为\((i,j)\)点树的数量,转移如下:
if s[i][j] == '*':
dp[i][j] = min(dp[i+1][j-1], dp[i+1][j], dp[i+1][j+1]) + 1
else:
dp[i][j] = 0
答案即为所有\(dp[i][j]\)的和。
这类\(DP\)问题貌似有名字,如果想知道可以去\(CF\)讨论里面看看(我忘记了,\(qwq\))
C - Random Events
给定一个长度为 \(n\) 的数组,给出 \(q\) 个操作 $( r , p ) $ 对$ [ 1 , r ]$区间进行有序排序,排序的概率是 \(p\) ,不变的概率自然就是$ 1 − p $。问最后数组全部有序的概率是多少。
巧妙的贪心:
一个性质:一旦数组被排序,它就永远不会未排序。
根据这个思路,可以发现,真正可以影响到整个数组的,其实是\(r\)大于等于最后一个不有序的位置的操作
例如\(n=4,[3,1,2,4]\),有序数组为\([1,2,3,4]\),显然在\(i=3\)的位置是最后不有序,那么\(r<3\)的操作都可以忽略,因为无论他们成功还是失败,这个位置都无序。
D - Divide and Summarize
给出一个数组,你可以操作\(0\)次或若干次改变这个数组。然后给出 \(q\) 个查询,问能不能找到一个数组和等于 \(s\)。
具体操作就是选取一个\(mid=[\frac{max(arry)+min(arry)}{2}]\) , 然后小于等于 \(mid\) 放左边数组,大于放右边数组,选择一个数组代替原来的数组
分治思想做法
式子里面只有最大值最小值,直接排序,最小值和最大值肯定是数组区间的第一个和最后一个,\(mid\)的位置也可以通过二分快速找到,就可以快速分割左右两个数组。
很明显这种分割是有限的(每次只能从大于\(mid\)和小于\(mid\)里面选一个),所以对原数组操作产生的所有可能和放在一个\(set\) 里面,查询的时候直接判断时候在里面即可
其他做法
可能有二进制做法,在讨论里面看到的,没看懂什么意思(大雾
E - Water Level
初始在饮水机中有\(k\)升水,每天需要消耗\(x\)升水,每天的一开始,\(John\)可以选择往饮水机中加\(y\) 升水(可以不加)。问\(t\)天内是否能保证每时每刻饮水机内的水大于等于\(l\)升,小于等于$r $升
有解分为两种情况,一种是无限天数都在范围内(循环),另一种是\(t\)天内在范围内
先把\(k-l\),\(r-l\)这样就能忽略掉\(l\)了,不然数据实在太大了,数据除了\(x\),其他都是\(10^{18}\)级别的
分类讨论一下:
若\(x>y\),水位每一天都会下降,如果一直加水,每天都会减少\((x-y)\),看看够用几天的(一定要注意前几天能不加水,别加超了)
若\(x<=y\),那么有个显然的贪心,让水位尽量低,这样可以给后面留下容错空间(表达不好,将就理解一下)
设\(k\)是当前水量,如果够一天的使用,则不加水,如果不够一天的使用则加水
如果\(k+y>r\),无解
如果\(k+y<=r\),这里就要判断一下会不会出现循环的情况(有解),\(k+=y\)然后\(k\%=x\),如果这时候的\(k\)出现过,那就有循环了,有解
如果\(t\)循环到\(0\)了,有解
F - Mathematical Expression
\(2700\)分的贪心+结论+DP,恐怖如斯
给一个长度为\(n(n\le 10^5)\)的序列\(a\),\(0 \le a_i\le 90\),现在给定你可以用\(+,-,*\)中的一些符号填到序列中\(n-1\)个位置上,使得最后的式子运算结果最大,乘法运算优先于加法与减法,请输出最后的式子
首先发现这里面有两个比较特殊的数\(0\)和\(1\)
对于\(0\),乘以\(0\)都是\(0\),对于\(1\),乘以\(1\)和没乘一样
先把问题分一下类
- 只有\(+,-,*\)其中一种
直接放即可
- 有\(+-\)两种
对于减法来说只会让答案变小,我们肯定是不用的,所以全用+
- 有\(*-\)两种
乘以\(0\)都是\(0\),所以只需要把第一个\(0\)用减号,其他都用乘即可
\(3*2*4*5-0*3*0*5*2\)
注意以后的\(0\)不用减法,因为减去的数越小答案越大
- 有\(*+\)或者\(*+-\)
减号显然直接不用,所以这两种是一类
显然,\(0\)的前后都一定是加号,这样我们就可以把序列用\(0\)拆分
拆分后,对于开头和结尾的\(1\),一定是用加号链接,例如$1\ 1\ 1\ 3\ 5\ 10\ 1\ 1\ 1 $
问题变为不含\(0\)且首尾均不是\(1\)的子序列,我们用\(+\)和\(*\)使其最大
直接用\(DP\)解决的话,会\(TLE\)
一个神奇结论:
如果当前序列的乘积大于长度\(2*N\)的时候,就直接全部乘法即可。否则里面最多有\(logn\)个数大于\(1\)
问题变为长为\(logn\)的数组,只用加和乘使得答案最大。
有了上面的结论,问题复杂度就可以转化为\(O(nlogn)\)了