GDKOI2017总结

来源:互联网 发布:java服务器与web服务器 编辑:程序博客网 时间:2024/05/10 05:09

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=01S=0S1S=01SS=S01S=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]的最优取值,很大可能L1是单调的。如果是单调的话,就是O(n^2)的了。但是实际上不是,有很大概率单调,有又一定概率不单调。那么我就随机往前跳一段。然而我随机跳地太多了,全部TLE了。看来我要好好复习下DP优化。

Day2:

T1:

题意:

给出一个[0..n][0..m]的矩阵,求满足条件的整点三角形的个数。条件:1、S为整数。2、至少有一条边和坐标轴平行。n,m<=10^9

题解:

这题的计数方法有很多。我的计数方法是这么算的:(有一条边与X轴平行的所有符合条件的三角形)+(与Y轴平行~)-(与x、y轴都平行~)先算有一条边与Y轴平行的所有符合条件的三角形。

三角形

假设与Y轴平行的边长为L,上端点为(x,y),h为高。显然x的取值为0~n-L,y的取值为0~m。接下来分情况:1、L为奇数,则h一定是偶数。

eqn1

前一半是x的取值,L=2i+1后一半是顶点的取值,h的取值有(m-y)/2种,顶点的x坐标取值为0~n-1。化简得m为奇数时:

eqn2

m为偶数时:

eqn3

2、L为偶数,那么h任取。

eqn4

化简得

eqn5

两个加起来,再乘以二(因为默认顶点在右边),就得到有一条边与Y轴平行的三角形的个数了。把n,m交换,就可以得到有一条边与X轴平行的三角形的个数了。根据容斥原理,我们还要减去与X、Y轴都平行的三角形的个数。首先算任取:

eqn6

设两条直角边长a、b,那么x、y的取值为[0,n-a]、[0,m-b]。然后减去a、b都是奇数的:

eqn7

把以上的式子都敲进去就可以了。

问题:

我写的时候,一开始验算时没写mod,后来改的时候,忘了把所有/2变成逆元。而且貌似乘完之后没有直接mod,爆掉了。

T2:

题意:

有n个人,每个人有两个属性a、b。每个人可以选择使用一个属性,排成一个第一项>H的最长上升序列,问长度。n<=10^5

题解:

这题一看就感觉DP,是不行的。然后我们转换一下:每个人可以选择一个属性,问>H的不同的属性最多有多少个。这就变成了二分图匹配,人在左边,属性在右边,每个人向属性连边。匈牙利算法显然超时,我写的是Dinic,跑过了。讲解的时候出题人给出了O(n)的正解:先把度为1的都匹配掉,迭代。剩下的图,左边的点度数都为2,右边的都>=2。考虑每一个环,都满足Hall定理,能完美匹配。那么右边的点数即为匹配数。

T3:

题意:

eqn8

n<=10^10另一组数据T<=5*10^4,n<=10^7

题解:

我一看就觉得是莫比乌斯反演裸题。然而莫比乌斯反演推出的公式极其复杂,还有n/i这样的项存在,实际上是不优的。这题最优情况是用欧拉函数。考虑每一个j的贡献。对于每一个i<j,(i+1)即1~j中每一个和j互质的数的和,再加上φ(j)。和j互质的数的和为:

eqn9

那么总的式子为:

eqn10

先不管j=1,我们可以之后加上。把式子稍微变换一下(顺便把j写成i,好看些。)

eqn11

那么我们要维护的就是φ(i)*(i^0..2)接下来就要用的是:杜教筛。我是从这里学的:

http://blog.csdn.net/skywalkert/article/details/50500009

eqn12

其中,a×b=c的意义是a函数和b函数的狄利克雷卷积为c函数。把c的前缀和按照狄利克雷卷积拆开,得到上面的式子。变换的过程如下:把所有数的约数列出来:1 12 1 23 1 34 1 2 45 1 56 1 2 3 67 1 78 1 2 4 8我们考虑从第i个数开始,它自己那里取走1,从2i那里取走2,从3i那里取走3。。然后就得到1~(n/i)的每一个数。例如从2 取走约数1,从4取走约数2,从8取走约数3……这样取完显然会把所有约数都取走,而且分解成1~(n/i)的和的形式。那么就能得到: 

eqn13

设a的前缀和函数为f。那么

eqn14

其中显然会有f(n)这一项,我们把它提出来。

eqn15

这样只要会求c和b的前缀和,就可以递归求a的前缀和了。注意到有n/i,所以可以用分块的方法优化。只要预处理小的前缀和,然后写个Hash,就可以在O(n^(2/3))的时间复杂度下求前缀和。然后我们看回原题。原题要求的是∑φ,∑φi,∑φi^2我们知道

eqn16

其中

eqn19
然后带入直接求就好了。

然后

i=1ni2=2n3+3n2+n6

eqn18

(考试时忘了,用高斯消元强行算的系数。)问题&&反思:不要看到像例题就觉得一定是例题。。。。其实莫比乌斯反演也是可以的,但是我考试的时候犯傻了。明明10^7以内直接预处理就好了,但是我每次都跑了个sqrt(n)的,然后就超时了。数论是学不完的,还要继续学。

T4:

题意:

有一个矩阵,矩阵四面都是墙。有以下的操作:在一个格子的某一面建墙。在一个格子的某一面拆墙。在两个格子的分别某一面墙之间,建传送门。拆传送门。从一个格子开始,往一个方向发射一条光线,问这条光线能走多少个格子?可重复计算,碰到墙就停止,经过传送门转到传送门面对的方向。如果停不下来就输出INF。n,m,q<=10^5

题解:

从暴力开始,考虑每个格子维护4个指针(指向自己的类型)。每个指针指向下一个格子相同方向的指针,表示到下一个格子,方向不变。建一面墙,将两个指针指向空。拆一面墙,将两个指针指向下一个格子相同方向的指针。建传送门,将两个指针指向传送之后的指针。拆传送门,将两个指针指向空。询问,从某一个指针开始走,直到为空或者循环为止。最需要时间的是询问,我们考虑用数据结构来维护。显然指针是一条链,这条链要求动态重新指向,而且能求某一段的长度。那么我们用Splay来维护比较方便,基于合并的Treap也行。建墙就把一棵splay拆成两棵。拆墙就把两颗splay合并成一棵。传送门同理。询问就把某棵splay的一个方向取出来求大小。实际上旋转到根然后求右子树的大小即可。注意有环的情况,如果有环,显然只会是从末尾接到开头。我们可以在splay的根记录是否有环。如果有环显然要输出-1。在拆分的时候,如果有环,拆完之后要把两端接起来。然后考虑数据范围,每一个格子建4个点显然不可能。我们把它离线离散化,每一个splay中的点实际表示一条线段,就可以满足条件了。在线也是可以写的,要复杂些。

问题&&反思:

正解很容易想,很难写,我不够时间就写了暴力。数据结构题还是要多写,限时写才行。

总析:

这次GDKOI的题目类型:

数学题:2。(Day2 T1 T3)DP题:2。(Day1 T3 T4)图论题:0~2。(Day1 T1 BFS也算的话 Day2 T2正解)数据结构题:1。(Day2 T4)网络流:1。(Day2 T2可以过)字符串:0。搜索:0。计算几何:0。杂题:1。(Day1 T2)

出现的问题:

知道正解不敢写。水题写错。思路误区。

未来方向:

多刷题。

Written By SemiWaker

1 0