GDKOI 2017总结
SemiWaker
总述:
这次GDKOI没有达到预期的成绩。一方面是因为做题能力不够,敲代码能力太弱,导致不够时间写正解,另一方面是思考方式还需要完善,有的知识点还需要进一步的学习。这次运气因素也是有的,这告诉我既然运气不好就要做到100%有把握。
题目&&题解:
Day1:
T1:
题意:
给出一个N*N字符矩阵,字符’P’表示玩家,’1’~’9’表示炸弹。
炸弹会在其表示的数字的时间点爆炸,使得上下左右4个方向的长度L的线段范围内被炸到。
炸弹被炸到会提前爆炸。
问玩家被炸到的最早时间。
炸不到输出-1。
N<=1000,炸弹数<=3000,L<=N
题解:
直接BFS即可。
暴力模拟炸弹的爆炸,将被炸到的炸弹放入队列即可。
只需要O(N)的时间,总时间复杂度O(N*炸弹数)。
问题:
不知为什么错了一个点。(可能是-1?)
T2:
题意:
有一个密码串S,S的构造法如下:
S=01
S=0S1
S=01S
S=S01
S=S1+S2
现在密码串开头和结尾都多出了一串,密码串中可能少了一个字符,问最长的合法的密码串长度。
N<=2*10^5
题解:
由构造法得出S是一个括号匹配序列,0和1匹配。
我们用一个栈记录0的位置,把S扫一遍就可以得到0和1的匹配。
不匹配的0和1最后会分割开原串,形成类似下面的形式:
...1...1..1..1..0..0..0..0..0...
前面的1是扫描中无法匹配到0的1,后面的0是扫描完之后栈中剩下的0。
注意到他们是没有本质区别的,所以记录位置即可。
如果不能增加字符,那么求出每一个合法段的长度的最大值即可。
如果能增加字符,那么相当于把两个相邻合法段合并,求出相邻合法段总长的最大值即可。
这题有很多做法,包括DP和模拟等,可以算是杂题。
T3:
题意:
有P*Q个人,编号0~P*Q-1。任意两个人x,y的距离是min(|y-x|,P*Q-|y-x|)
如果x和y的距离是P或Q的倍数,那么x和y相邻。
要求将图划分为任意个圈,使得每一个圈人数>=3,求方案数。
P<=6 Q<=10^9
题解:
插头DP。
首先,每一个点是4连通的。
那么这个图很有可能可以画成矩阵状,实际上是可以的。
这个图的实际几何形状是“甜甜圈”状,画成平面就是矩阵,上下边界连通,左右边界连通。
考虑数据范围,P小Q超大,显然是对于P做DP,然后对于Q做矩阵乘法。
什么DP可以求划分圈方案数呢?实际上这是插头DP的例题。
一对边界变成环也是可以做的。
现在剩下两个个问题。
第一个问题:另外一边的边界也是环。
我一开始的想法是:暴力枚举第一行,然后再DP。
然而结合矩阵乘法可以得到一个简单的方法:对于转移矩阵的主对角线上的状态,表示转移到相同的状态。那么如果我们直接求转移矩阵的Q次方,主对角线上的系数和就是答案。
这是矩阵乘法优化DP的一个变形应用:直接计算转移矩阵,不管初始状态向量。
第二个问题:怎么记状态?
如果按照折线扫描线的普通记法,单行状态数会比较多。
但是我们可以回到原始的方法:一整行作为一个状态。
这种方法的问题是转移比较慢,但是放进矩阵乘法就没有区别了,都是O(n^2)。
这给我们的启示是:对于状压DP的矩阵乘法,直接一整行作为状态会比较优。
状态数有多少呢?
如果用括号匹配,是36种,但是要解码和编码。
这题有特殊性:它不在乎有多少个环。
那么每一个连通块就没有必要编号。
所以直接2^6表示每一个位置有没有插头,也是可以的。
实际状态会比括号匹配还少,不过要求实际状态的话还是要解码和编码。
因为2^18可以过,所以直接记即可。
问题及启示:
知道是插头DP,没敢编,而且细节问题也搞不定。
要写多几次插头DP,多思考细节问题。
T4:
题意:
有一个序列,每次可以从左边或者右边取一段,将他们放入一个“袜子”里。
“袜子”有两个容量V和W,要求分别满足体积不超过容量。
求最少需要多少个背包才能装下整个序列。
n<=3000
题解:
很容易得到一个简易的DP模型:
F[L][R]=min(F[L1][R1]+1) L1<=L R1>=R
使得L~L1-1和R1+1~R的总和不超过容量。
这个是一个O(n^3)的。(L1和R1关联,算一个变量。)
然后我们考虑怎么优化。
直接从方程来讲,没什么好优化的。
我们可以考虑合并状态。
把F[L][R]这个状态表示为:已经取到L和R的时候,最少的“袜子”数和已经放入的物品的总和。
这样每次我们可以考虑只取最左边和最右边。
那么转移方程变为F[L][R]=min{F[L+1][R]+0/1,F[L][R+1]+0/1)
现在的问题是:已经放入的物品的总和是一个什么样的状态?
假如只有一种容量,那么记录放入的物品的总体积就可以了。
这种状态下,两个F先比较袜子数,再比较总体积就可以确定优劣了。
但是有两种容量的话,两个体积之间无法取舍,是无法满足最优性的。
我们需要寻找另外一种记状态的方法。
比如说,记录L左边已经选了多少个。
这样显然选的越少越好。
那么右边怎么办呢?我们可以考虑二分一个位置R1,使得加上R刚好取满。
这里转移到F[L][R1] 袜子+1 左边选的长度=0
另外一种转移是左边多选一个 F[L+1][R] 再判断是否装满。
这样就变成O(n^2logn)的了。
问题和启示:
我当时用的是一个随机的方法:
考虑最原始的转移方程,L1的位置的取值。
考虑F[L][R]和F[L][R-1]的最优取