[链接]
想写SAM结果自闭了。
线段树历史最大值模板题。
注意到其实带维护历史最大值最大的问题时维护tag。
这里我们将tag维护成 ( a , b ) (a,b) (a,b)表示当前这个tag会把 max ( v + a , b ) \max(v+a,b) max(v+a,b)。
那么加法就是 ( v , − i n f ) (v,-inf) (v,−inf),赋值就是 ( − i n f , v ) (-inf,v) (−inf,v)。
可以发现 max ( v + a , b ) \max(v+a,b) max(v+a,b)是一段常函数+一段一次函数,对于每个历史上的每个函数的最大值的函数就是 max ( v + max a i , max b i ) \max(v+\max a_i,\max b_i) max(v+maxai,maxbi)。
因此我们再维护一个历史最大 t a g tag tag为 m t a g mtag mtag,每次从父节点下传的时候将当前节点的 t a g tag tag与父节点 m t a g mtag mtag合并之后的tag对该节点的 m t a g mtag mtag更新即可。
考虑合并两个tag ( a , b ) , ( x , y ) (a,b),(x,y) (a,b),(x,y)就是 ( a + x , m a x ( b + x , y ) ) (a+x,max(b+x,y)) (a+x,max(b+x,y))。
根据辗转相除法 gcd ( a l , a l + 1 , . . . , a r ) = gcd ( a l , a l + 1 − a l , . . , a r − a r − 1 ) \gcd(a_l,a_{l+1},...,a_r)=\gcd(a_l,a_{l+1}-a_l,..,a_r-a_{r-1}) gcd(al,al+1,...,ar)=gcd(al,al+1−al,..,ar−ar−1)。
这样我们就可以维护带区间修改的区间gcd查询了。
插头dp入门题。
学习链接
插头dp——从入门到出门
这种超级大分类讨论简直是魔鬼。
这也是一道很模板的题目。
注意题目不要求每个格子都要走,因此要加一种情况。(害我调了半天)
比模板题简单一些。
因为是要求找两条不相交的路径,我们没必要用括号序列来描述。因此我们用一个3进制数0/1/2保存没有插头/A类插头/B类插头然后暴力分类讨论转移即可。
细节:注意转移到下一行的时候要判最高位的01状态…否则会RE…
于是我又调了半天
这道题目让我领悟到了:插头dp≌超级无脑大暴力。
不得不说为什么ACMer多的地方题解都很短很短啊qwq。
最后找到了cdq的论文,写的很清楚,这里存一下:
一道挺好的题目,但是因为可以打表被玩坏了…
考虑贴着矩形的边框画一条轮廓线,那么在轮廓线内的就是黑色,在轮廓线外的就是白色。
考虑如何将轮廓线限制在边框上。注意到可以转化为从左上角的边框开始画,离开矩形边框的次数严格为2。因此我们让dp再加一维表示当前离开矩形边框的次数为多少即可。注意要减去全黑的情况。
实测跑起来极快,但是还是没打表快。
当然,你可以选择直接dfs在轮廓线上搜索。这样代码会好写很多。
按理来说我应该用上一道题的最小表示法改的…但是…
很抱歉,调不出来。
于是就找了网上唯一一份括号序列代码借鉴了一下。
一眼题,不说了。
突然想起CSP day2T1我就是被这种东西给带偏的。
其实我之前做过这题。差点自己没做出来
这题算是dp套dp的经典入门题目吧。
如何将一个dp套在另外一个dp上面?我们通过一些特殊的hash技巧,将内层dp的结果压缩成一个状态作为外层dp的一维。
例如本题我们考虑设定内层为LCS dp数组,考虑将其结果压缩成一个状态进行dp。
注意到LCS dp中对于固定的 i i i,此时 j j j与 j + 1 j+1 j+1相差最多为1且不下降。因此我们直接用二进制存储这个dp相邻位置的差值。
那么外层dp就定义为 f [ i ] [ S ] f[i][S] f[i][S],表示在 t t t串中已经加入 i i i个字符使得内层dp结果为 S S S的方案数。每次转移就在末尾加一个字符即可,变为 f [ i + 1 ] [ t r a n s [ S ] [ k ] ] f[i+1][trans[S][k]] f[i+1][trans[S][k]]。
t r a n s [ S ] [ k ] trans[S][k] trans[S][k]表示当前dp数组在 t t t串加一个 k k k字符变成的状态。显然这个可以预处理得到答案。
复杂度: O ( T ( ∣ S ∣ 2 ∣ S ∣ + m 2 ∣ S ∣ ) ) O(T(|S|2^{|S|}+m2^{|S|})) O(T(∣S∣2∣S∣+m2∣S∣))。
感觉独立想出来还是有些困难。
回忆一下 O ( n log n ) O(n\log n) O(nlogn)单调栈求最长上升子序列的过程,我们在栈中增加一个数,将它的 l o w e r _ b o u n d lower\_bound lower_bound的数替换掉。
考虑将这个dp当作内层dp
为什么JOI Final会有这种签到题啊qwq。
仔细想想,你会发现是一道拓补排序模板题。
感觉画风突变…
正解感觉很神仙,但是被初三的同学用 O ( 2 n / 2 ∗ n 3 log n ) O(2^{n/2}*n^3\log n) O(2n/2∗n3logn)过了。
首先很抱歉我dp学傻了想了半天 O ( n 5 ) O(n^5) O(n5)dp发现状态始终与权值大小有关。
后来才开始想meet in meddle,很容易就能够想到 O ( 2 n / 2 ∗ n 3 log n ) O(2^{n/2}*n^3\log n) O(2n/2∗n3logn)的做法。但是我太不相信wls的电脑速度了,认为这种做法会T掉。
然后就偏到分治上面去了。感觉可以分治,但是怎么做都有点问题。
然而正解就是分治…
摸底考试6科全炸,我太快乐了…
插头dp好题。
显然先考虑原地图答案该怎么求。我们可以将一个 1 × 2 1\times 2 1×2的骨牌看作是一个向下/右的插头。
那么我们设 f [ i ] [ j ] [ S ] f[i][j][S] f[i][j][S]为已经确定了前 ( i − 1 ) × m + j (i-1)\times m+j (i−1)×m+j格子的插头状态,当前轮廓线状态为 S S S的合法方案数。
dp即可。
现在考虑修改一个格子。根据套路显然我们会再设一个数组 g [ i ] [ j ] [ S ] g[i][j][S] g[i][j][S]为已经确定了除了前 ( i − 1 ) × m + j (i-1)\times m+j (i−1)×m+j格子的插头状态,当前轮廓线状态为 S S S的合法方案数。(也就是说再倒过来跑一遍)
假设我们在 ( i , j ) (i,j) (i,j)上将答案合并起来。考虑枚举 S S S,显然 j j j和 j − 1 j-1 j−1位不能够为 1 1 1。注意到如果 f f f的 S S S中一个位置有插头,那么 g g g的 S S S中一个位置也必须有插头。因此答案就是 ∑ S f [ i ] [ j − 1 ] [ S ] × g [ i ] [ j + 1 ] [ S ] \sum_{S}f[i][j-1][S]\times g[i][j+1][S] ∑Sf[i][j−1][S]×g[i][j+1][S]。
复杂度: O ( n m 2 n ) O(nm2^{n}) O(nm2n)
IOI2016签到题/
正着/倒着dp一遍合并起来即可。
看成求方案数自闭了半天…
注意到题目满足 u − l ≥ w m a x − w m i n u−l≥w_{max}−w_{min} u−l≥wmax−wmin
显然大胆猜测一定存在一个解使得在排序后的数列编号连续。
没了。
证明看书。
在考虑下轮互测用:)
[UR#1]外星人
KMP板题。考虑前缀函数只与前面的串的内容有关,因此删去末尾 m m m个字符不用考虑前面的字符。
仍然按经典的KMP来做,唯一不同的就是 S S S串需要我们用栈动态维护。
复杂度: O ( n ) O(n) O(n)
还是以KMP算法本身入手。注意到一个数组的逆序对数组是唯一的,因此我们用这个来进行hash匹配。
于是我们在 S S S串中用树状数组动态维护逆序对,因为KMP算法本质上是一个单调递增的双指针,因此修改/增加的均摊复杂度是 O ( n ) O(n) O(n)。
复杂度: O ( n log n ) O(n\log n) O(nlogn)。
刷水题愉悦身心:)
n , m ≤ 3 n,m\leq 3 n,m≤3的情况特判,其余的找规律。
非常经典的Atcoder风格的题目。
首先显然这题和字符串循环节有关系,于是我们考虑讨论 S S S的循环节对答案的影响。
判断切点我们可以前后各做一遍KMP。
复杂度: O ( n ) O(n) O(n)
这是一道找规律题。
显然最终的结果可以由原串和原串长度最小的循环节拼接而成,接下来考虑找规律。
[自己手玩一会后发现]
设一个串为 S S S,它的最短周期为 T T T
S = a b a , T = a b S=aba,T=ab S=aba,T=ab
a b a ∣ a b a − > a b a a b ∣ a b a a b − > a b a a b a b a ∣ a b a a b a b a − > a b a a b a b a a b a a b ∣ a b a a b a b a a b a a b aba|aba->abaab|abaab->abaababa|abaababa->abaababaabaab|abaababaabaab aba∣aba−>abaab∣abaab−>abaababa∣abaababa−>abaababaabaab∣abaababaabaab
即 S ∣ S − > S T ∣ S T − > S T S ∣ S T S − > S T S T S ∣ S T S T S S|S->ST|ST->STS|STS->STSTS|STSTS S∣S−>ST∣ST−>STS∣STS−>STSTS∣STSTS。
由于要迭代无限次,我们只需要保留这个字符串的前一半。
注意到这个字符串类似斐波拉契排列,而斐波拉契增长极快,因此直接递推求解即可。
下轮互测题。
随便区间dp
有点反感AT/JOI比赛的这一类题目,因为我智商不够(雾)。
通过各种找规律发现合法的边肯定是所有奇环的交,并且不再任何偶环上。
然后我们考虑建一颗dfs树
考虑用trie树辅助建树后贪心即可。
AC自动机复习
P3808 【模板】AC自动机(简单版)
[POI2000]病毒
P3121 [USACO15FEB]Censoring G
P2292 [HNOI2004]L语言
P4045 [JSOI2009]密码
[AGC022E] Median Replace
P2414 [NOI2011]阿狸的打字机
CF86C Genetic engineering
P3082 [USACO13MAR]Necklace G
CF696D Legen…
CF163E e-Government
咕了的题:BZOJ4231 回忆树
模拟考试
首先很容易得到原式的递推方程。
容易得到一个矩阵快速幂的做法,这样是 O ( k 3 ) O(k^3) O(k3)。
然后我们写成多项式的形式,多项式快速幂暴力卷积 O ( k 2 ) O(k^2) O(k2)。
前天晚上失眠,中午一事无成…
复习一下午的SAM,仿佛SAM的奇怪的知识又增加减少了。
首先显然是一道状压dp的题目。
定义 f [ S ] f[S] f[S]为当前已加入的点集为 S S S,这些选中的点之间的边互相连通的方案数。
直接做显然很麻烦,一个熟练的OI选手肯定会想到使用容斥/反演。
那么我们再定义 g [ S ] g[S] g[S]为使选中的点不一定连通的方案数。
有:
f [ S ] = g [ S ] − ∑ T ⊂ S 且 l o w b i t ( S ) = l o w b i t ( T ) f [ T ] g [ S − T ] f[S]=g[S]-\sum_{T⊂S且lowbit(S)=lowbit(T)} f[T]g[S-T] f[S]=g[S]−T⊂S且lowbit(S)=lowbit(T)∑f[T]g[S−T]
注意 l o w b i t ( S ) = l o w b i t ( T ) lowbit(S)=lowbit(T) lowbit(S)=lowbit(T)是为了防止算重复。
这样复杂度是 O ( 3 n ) O(3^n) O(3n)的。
接下来我们考虑用FST优化,这里需要求逆。
详见这里我懒得写了。
复杂度: O ( 2 n n 2 ) O(2^nn^2) O(2nn2)
2-SAT被我忘得一干二净…
首先我们只知道我们确定了一行一列的方案数,我们一定能够得到原矩阵的一个解。
由于我们只能够填0/1两个数字,我们很容易想到2-SAT。
如何建立这些位置之间的限制关系呢?
通过打表我们可以发现一个位置 ( x , y ) ( x < n , y < m ) (x,y)(x
因此我们枚举 A n , m A_{n,m} An,m的取值, A x , m , A n , y A_{x,m},A_{n,y} Ax,m,An,y之间一定会有某些限制关系,连边即可。
tip:注意复习一下2-SAT的方案输出。
其实是一道很模板的2-SAT问题。
首先 d = 0 d=0 d=0的情况就是模板。
接下来考虑 d > 0 d>0 d>0的情况,由于 d d d很小,我们可以直接通过枚举这几个特殊位置选不选这个格子的第三种选择来使得原问题变为2-SAT问题。
具体来说我们可以通过类似 i − > i + n i->i+n i−>i+n这样的连边来满足枚举的子集的要求,这样我们跑 2 d 2^d 2d次2-SAT即可。
复杂度: O ( 2 d m ) O(2^dm) O(2dm)
codeplus7体验日。
上午彩蛋题跟同学开黑得了满分。
下午就自闭了。
一直往BFS方向想结果花了半个小时,自闭了。
这其实是一道物理题目…
根据碰撞原理我们知道碰撞后两物体速度会交换,那么,如果我们希望两物体速度不交换,我们可以将其看成两物体速度不交换,路程交换。
根据动量守恒,我们知道最后从左边出去的物体的个数一定等于最开始向左的物体个数,右边同理,因此我们得到了所有蚂蚁的路程值,但现在来看不一定与蚂蚁初始编号一一对应。
但是我们知道蚂蚁的相对位置是不变的,因此我们依次按向左(小到大)向右(大到小)的顺序输出即可。
NOI Online 3爆炸日
总结在此
首先你要弄清楚题目中的操作在在做些什么,通过打表等方式分析可以知道你每次可以在一个 ( x , y ) − ( n , m ) (x,y)-(n,m) (x,y)−(n,m)的矩形内加一个斜着的杨辉三角,但是须要去掉顶部的大小为 k k k的三角的值。
注意到所有的操作递推公式一样,因此可以一开始赋好初值之后最后一起递推。
但是对于一开始的初值须要修改 O ( q n ) O(qn) O(qn)次,会T。
注意到 k k k与 k + 1 k+1 k+1之间也有递推关系,因此我们这样做:
对于 ( u , v , k ) (u,v,k) (u,v,k)操作, d p [ u ] [ v ] [ k ] + + dp[u][v][k]++ dp[u][v][k]++。进行完所有操作后, d p [ u ] [ v ] [ k ] + = d p [ u − 1 ] [ v ] [ k + 1 ] + d p [ u ] [ v − 1 ] [ k + 1 ] dp[u][v][k]+=dp[u−1][v][k+1]+dp[u][v−1][k+1] dp[u][v][k]+=dp[u−1][v][k+1]+dp[u][v−1][k+1]。进行完这一步后, d p [ u ] [ v ] [ 0 ] + = d p [ u − 1 ] [ v ] [ 0 ] + d p [ u ] [ v − 1 ] [ 0 ] dp[u][v][0]+=dp[u−1][v][0]+dp[u][v−1][0] dp[u][v][0]+=dp[u−1][v][0]+dp[u][v−1][0]。
复杂度: O ( n 3 ) O(n^3) O(n3)
跟某道AGC的题目比较类似。
半期考试啊啊啊啊啊啊啊啊啊口阿口阿口阿口阿口阝可口阝可口阝可口阝可口阝可。