9.week3
今天也是大摆特摆的一天
关灯
自己模拟了一下,发现是九连环?
对于玩过的人来说这个就很好推了.
当我想要取反当前状态的话,我需要前面的所有有且只有上一个是亮着的
那么我们就可以开始递推了.
这里我们分两个dp来转移更方便.
一个是\(f[i],表示进行到当前位的步数和\),\(另一个是dp[i],表示只让i位置亮的步数\)
dp[i]=dp[i-1]+1+dp[i-1]
if(a[i])f[i]=dp[i]-f[i-1]
else f[i]=f[i-1]
稍微解读一下:
首先dp的递推很明显.
\(!a[i]的话答案直接继承\)
否则是根据九连环步骤的可拆分计算可以减掉的步骤达到递推
简单来说这一位是1的话,你设想的\(dp(最大步骤)\)就可以跳过这一环节了.
虔诚的墓主人
粘一个形式化题意:
在$ n×m $一个方格上给你 $w $个点,求方格里每个点正上下左右各选 \(k\) 个点的方案数。
直接算答案\(W^2\),我们来扫描线.
一竖条一竖条地走.
我们可以对大段的空白统一计算答案贡献
对于两点\((x,y1),(x,y2)\)
有答案贡献:
主要是怎么快速求出这个后半部分.
可以BIT.
注意每次加入一个点的操作是加\(\Delta\)
实现起来还是有不少细节问题.
电脑班的裁员
直接连续段dp就是的了
我们需要加一个状态或者是再开一个数组来记录最后一点是否选择.
如果选择,我们可以新点合并入段,也可以再开
当然贪心来说,一定是选择合并
如果没有选最后一个点,那么只能新增段
当然你可以不选这个点.
这样dp的转移就很清楚了
由于段只会变多,所以说你甚至可以滚动一下.
贴一小段转移:
g[j]=max(g[j],f[j-1])+a[i];//连上去
f[j]=max(f[j],g[j]);//选还是不选
KOŠARE
\(SOSdp,高维前缀和\)
当我们要求子集的贡献时使用
贴个学习笔记
现在具体的谈这个题目
\(m\)很小,状压.
我们发现这个问题可以抽象一下
就是从\(1e6\)个\(m\)位的二进制码,选出数按位或起来是1
具体到某个状态的不好求
但是我们可以求出一个前缀和然后差分.
具体来说,是我可以求出到 \(i\) 状态子集的所有方案
F(i,0,m-1)
F(j,0,(1<<m)-1)
if(j&(1<<i))
f[j]=(f[j]+f[j^(1<<i)])%mod;
以上代码就是所谓高维前缀和,其实就是按位考虑自己能从谁转移过来然后逐位进行从而得出一个前缀和
那么我们知道对于\(i状态和他的子集\)来说,所有的合成方案就是\(2^{f[i]}\)
求出这个后,我们再对这个前缀和做一个高维意义下的差分,对应答案就出来了啊.
很巧妙.
基站建设
本周重头戏,李超线段树
具体的李超线段树贴一个数据结构blog的链接
现在我们来考虑李超线段树的实际运用.
先拿出转移式子:
然后对式子变形:
明显的斜率式子.而且斜率不单调.
我们想要是最小,注意初始化问题.
后面就是直接对\(x\)的值域范围开李超线段树了,记得动态开点
没了,就这.
Beautiful Subarrays
这个还是挺简单的.
我们直接查询符合要求的前缀和就行.
对应\(i\)位置的查询,我们可以直接按位模拟.
对应当前位置为1,说明必须选择和当前位置不同的节点.
否则是两者都行,加上一颗子树的然后继续跑另一颗子树
注意这里主要强调一点.就是trie的开始节点是谁.
我们这里的操作很粗糙,很容易走到不存在的点上,这是不合法的,点的对应编号是0.
但是我们的0是有意义的,这会导致代码出错.
所以说,选择1为trie的开始是明智的.以后养成这个习惯.
tot也要初始化为1.
A Simple Task
首先是\(O(logn*26)\)的线段树做法
每次取出对应区间的所有字母合集,然后一个一个放回去
你发现这个属于一个推平操作。
你选择ODT来解决这个问题。
ODT的优势在这里很大。
因为你的合并长度一旦超过了26,就会出现一段的合并。
很不好卡,或者说复杂度本身就是对的。
每次合并只会插入26个节点,所以说复杂度是\(O(mlog(n+26))\)
然后常数还要小很多。
加法
一个贪心的思路是每次找到最小的位置然后加值。
再想想发现不好写。
你觉得你可以二分来做
对于每个区间,对其进行排序。
扫到 \(i\) 位置时,如果小于mid就加上一个区间。
为了更优,我们就选择右端点最靠后的。
这样就做完了。
robots 机器人
继续贪心。
首先二分。
我们优先让弱机器人选择,每次选择可以选的玩具中,Y限制最大的,然后再然小机器人收拾残局。
贪心明显没有什么问题。

浙公网安备 33010602011771号