08 2013 档案
摘要:Nim游戏:有n堆石子,每堆个数不一,两人依次捡石子,每次只能从一堆中至少捡一个。捡走最后一个石子胜。先手胜负:将所有堆的石子数进行异或(xor),最后值为0则先手输,否则先手胜。================================Anti-Nim游戏:游戏与Nim游戏基本相同,只是捡走最后一个石子者输。先手胜负:将所有堆的石子数进行异或(xor),如果异或结果为0且所有堆的石子数全为1,或者异或结果为0且存在数量大于1的石子堆,则先手胜。否则先手输。该题即是Anti-Nim游戏,知道判定的规则后很简单。 1 #include 2 #include 3 using namespac
阅读全文
摘要:题意:一个仅有一行的棋盘上,初始时有n个棋子,每人轮流移动棋子,每次只能移动一枚棋子,棋子在移动时只能向左移动,不能跨过别的棋子或跳出棋盘。思路:这道题是一道nim游戏的巧妙变形,太棒了。解决的思路是,将所有棋子的初始坐标从小到大排序,从最后一枚向前两两配对。如果棋子数为奇数,则将第一枚与坐标0配对。这样配对之后,如果移动一对中靠左的棋子,后一个人总可以移动靠右的那一枚棋子来保持两枚间距不变。这样靠左的棋子和前一对中靠右的棋子的距离就可以不需要考虑了,因为是不影响胜负的。唯一影响胜负的就是一对中的两枚棋子的距离。把所有对中的两枚棋子的距离看作一堆堆的石子,则可以把缩短距离看作捡石子,这样子谁先
阅读全文
摘要:题意:n枚硬币围成一个圈,每次每个人可以从中取走一枚或者相邻的两枚(如果两枚硬币原本中间隔着一枚硬币,后来被取走,这两枚硬币不算相邻)。谁取走最后一枚硬币谁就赢了。思路:我们可以找找规律。首先,n为1和2的时候肯定是先手胜。n为3时,无论先手取1枚还是2枚,都会输。当n大于等于4时,我们分成两种情况来讨论。如果n为偶数,对于后手来说,总可以根据先手的做法,在对称的位置取走相同数量的硬币。先手必输。如果n为奇数,对于后手来说,总可以在某处取走硬币后,使得剩下的硬币分成对称的两组,然后依照n为偶数时的策略就能赢。此时也是先手必输。下面举个例子,假设n为5时,后手的策略如下图:PS:终于明白为什么这
阅读全文
摘要:题意:威佐夫博弈。思路:看了很多证明都没看懂。最后决定就记住结论好了。对于所有的奇异局面(必败局),有通项公式Pi = (a, b), (a = i * [(sqrt(5) + 1) / 2], b = a + i) 其中[]表示取整,如[3.9] = 3, [4.1] = 4。那个(sqrt(5) + 1) / 2就是传说中的黄金分割了。根据这个通项公式,可以发现a与b之间的关系,a = (b - a) * [(sqrt(5) + 1) / 2]。因此对于一个给定的局面(a, b),只要判断其是否有这个关系就知道是不是必败了。此外还要注意,如果a > b,应将两者的值互换一下,这是为了
阅读全文
摘要:题意:两个人做游戏,每个人都可以在自己的回合里将数p乘以2到9之间的一个数,初始时p=1,谁先将p乘到大于等于n就算赢。思路:一开始我算sg值,结果算来算去都没算明白。。。后来看了别人题解,才豁然开朗。首先,对于一个数m,计算出p在什么范围内可以乘到大于等于m。该范围即为[ceil(m/9), m - 1]。其中ceil()为向上取整。如果将每一个数字都看作一个局面的话,则在该区间内的点即为N点。对于一个数m,计算出p在什么范围内只能乘到大于等于m。该范围即为[ceil(m/2), m - 1]。如果将每一个数字都看作一个局面的话,且m对应的局面为N点时,则在该区间内的点即为P点。考虑到int
阅读全文
摘要:题意:略。思路:用dp[i][k]来表示结点i给k个用户提供节目时的最大盈利(可能为负)。则递推方程为: dp[i][j] = max(dp[i][j], dp[i][m] + dp[v][j-m] - cost)其中v为i的孩子,cost为i向v提供节目的花费。另外注意代码里dp过程的这几行1 for (int j = num[x]; j >= 0; j--)2 for (int k = 1; k 2 #include 3 #include 4 #define maxn 3005 5 #define inf 0x3f3f3f3f 6 using na...
阅读全文
摘要:题意:一棵树每个结点上都有值,现删掉一条边,使得到的两棵树上的数值和差值最小。思路:这个题我直接dfs做的,不知道树状dp是什么思路。。一开始看到数据规模有些后怕,后来想到long long 可以达到10^18,我突然就释然了。整体思路就是,先记录下整棵树的数值之和tot,然后对这棵树进行一遍dfs,每个结点都维护一个num值,num[x]表示结点x和它子树上的数值和。每求出一个结点的num值,就计算下tot - num[x]和num[x]的差值。dfs结束后最小的差值即为结果。另外,要注意的一点是,如果用res来存储最后结果,初始化应为无穷大,而因为它是long long类型,可以初始化为0
阅读全文
摘要:题目:一棵树,每个结点上都有一些苹果,且相邻两个结点间的距离为1。一个人从根节点(编号为1)开始走,一共可以走k步,问最多可以吃多少苹果。思路:这里给出数组的定义:dp[0][x][j] 为从结点x开始走,一共走j步,且j步之后又回到x点时最多能吃到的苹果数。dp[1][x][j] 为从结点x开始走,一共走j步最多能吃到的苹果数(不必再回到x点)。之所以要定义上面的一种状态是因为在求第二种状态时需要用到。下面介绍递推公式。对于结点x,假设它目前要访问的孩子为y,则1...(y-1)已经遍历过。此时有:dp[0][x][j+2] = max(dp[0][x][j], dp[0][x][m] +
阅读全文
摘要:题意:一只蜗牛将壳忘在了一棵树的某一个末结点(叶子)上。它想找回自己的壳,但忘记是丢在哪个结点上了,只好从树根开始网上爬,一个结点一个结点地找。在一些结点上居住着毛毛虫,它们会告诉蜗牛该结点以及它的子树上是否有它的壳,这样可以节省些时间。两个结点如果相连,则距离为1。问蜗牛找到壳的最小期望距离为多少。 接着给了一个例子(上图): 假如蜗牛以结点2,4,5的顺序找,则壳分别在结点2,4,5时它需要爬行的距离为1,4,6。则它找到壳的期望为(1 + 4 + 6) / 3 = 11/3。 考虑另一种情况,假设蜗牛先往结点3的方向爬,而在结点3处有毛毛虫,它可以告诉毛毛虫有关壳的信息...
阅读全文
摘要:题意:略。思路:由于每个大炮射程为2,所以如果对每一行状态压缩的话,能对它造成影响的就是上面的两行。这里用dp[row][state1][state2]表示第row行状态为state2,第row-1行状态为state1时最多可以安放多少大炮。则递推公式为:dp[i][K][J] = max(dp[i-1][L][K] + num[J])。其中num[J]表示状态J的二进制形式里有多少个1。代码我是参考的别人的,觉得写得很好。主要有一下几个地方:1. 在判断一个数二进制形式有多少个1时,用 x & (x - 1) (具体见代码count_one函数)来判断。这种方法的时间复杂度就是x的二
阅读全文
摘要:题意:略。思路:这一题开始做的时候完全没有思路,便去看了别人的题解。首先,对于这个题目解法想有一个初步的了解,请看这里:http://www.2cto.com/kf/201208/146894.html根据这篇讲解,写了一篇扭曲的代码,提交之后TLE。经过排查分析之后发现,算法的复杂度为O(hw*(2^(2w))),这个复杂度肯定超了。后来进行了优化,如果两种状态可以匹配,就将它们用邻接表(vector实现)存储起来,这样只需一遍预处理,以后直接读取就可以了。此外,还有两个地方的优化:1. 如果h*w为奇数,则结果必为0。(每个砖块的面积为2,无法用整数块铺满)2. 如果h 2 #inclu.
阅读全文
摘要:题意:略。思路:第一次做状态压缩的dp。在这里说一下状态压缩的原则。因为每一行只有最多12个格子,每个格子只有1(可放牛)和0(不可放牛)两种状态,这总共是2^12种状态,直接用一个int整型变量从0枚举到2^12 - 1。对于每一个数,将其转换成二进制,先判断格子为0时该数二进制对应位上是不是1,若是则该状态不可行。其次再判断该数相邻的两位有没有同时为1的情况,如果有,该状态也不可行。递推公式就是:dp[i][k] = dp[j][k-1]。其中dp[i][k]表示在牧场第k行状态为i时可行解的数量。它等于上一层所有可行状态的可行解数量之和。在dp过程中,在判断该层的上一层某状态是否可行时,
阅读全文
摘要:题意:略。思路:第一次写的时候搞复杂了,弄得跟计算几何似的= =递推公式很好想,就是dp[x2][y2][t] = max(dp[x2][y2][t], dp[x1][y1][t-1] + online(x2, y2, x1, y1)。其中dp[x2][y2][t]表示在时间点t锤子选择砸到点(x2, y2)处时的最大积分,点(x1, y1)与点(x2, y2)距离不大于d,online函数计算的是以这两点为端点的线段上有几只地鼠。另外,本题中锤子可以砸到坐标系外面,如果不考虑此种情况会wa。处理方法是,读取坐标时横纵坐标都加5(5为锤子可移动距离d的最大值)。更多细节见代码即注释。 1 #i
阅读全文
摘要:题意:略。思路:大家多看看题目当中这个图发现每次蜘蛛侠在空中发射蛛丝的位置都是与起点公寓的高度相同的(高中物理机械能守恒)。因此这个高度就不用计算了。题目的重点是想出dp的递推公式。现在先考虑一个问题,已知一栋大楼j的高度和x轴坐标和起点公寓的高度(公寓高度决定了蜘蛛侠发射蛛丝的高度),在x轴坐标多少范围内蜘蛛侠可以成功发射蛛丝荡过该大楼呢?考虑极限情况,蜘蛛侠荡到最低点时正好贴着地面,则此时蛛丝的长度为大楼j的高度h[j]。则在距离地面高度为h[1](起点公寓的高度)时蜘蛛侠发射了该蛛丝,此时与大楼j的水平距离为sqrt(h[j] ^ 2 - (h[j] - h[i]) ^ 2)设该点为st
阅读全文
摘要:题意:不想复述了。。好累。。思路:yey矿只能由东向西运送,用数组yey[i][j]表示地图中从(i, 1), (i, 2), ... 到 (i, j)的yey矿总量。blog矿只能由南向北运送,用数组blog[i][j]表示地图中从(1, j), (2, j), ... 到 (i, j)的blog矿总量。而dp[i][j]表示左上顶点为(1, 1),右下顶点为(i, j)的矩形内按照题意可运送的矿产总量的最大值。则关键点就是位于(i, j)处的矿产。可以有两种选择,一种是从该点建一条向北的blog矿的传送带,另一种是从该点建一条向西的yey矿的传送带。由此可得dp的递推公式:dp[i][j]
阅读全文
摘要:题意:平面上有一些给定的点,用一个给定大小的矩形(不能旋转)来框住最多的点。思路:预处理出所有左上顶点为(1, 1),右下顶点为(x, y)的矩形里点的数量,用dp[x][y]存储。我也不知道这种方法是不是dp。。。总之,题很水。 1 #include 2 #include 3 #include 4 using namespace std; 5 int dp[110][110]; 6 int main() 7 { 8 //freopen("data.in", "r", stdin); 9 int n;10 while (~scanf("%d&q
阅读全文
摘要:题意:给一个字符串,通过删除字符或者添加字符将它变成回文串。给出删除或添加每一个字符的费用,求最小费用。思路:刚开始学习dp,觉得dp最重要的就是发现问题与子问题的递推关系了。这里用dp[i][j]表示字符串从i到j变成回文串的最小花费。假设id[i] = id[j],则dp[i][j] = dp[i+1][j-1]。如果不相等,有dp[i][j] = min(dp[i+1][j] + cost[ id[i]-'a' ], dp[i][j-1] + cost[ id[j]-'a' ])。具体分析如下假设i到j构成的子串为akkk...kkkkd,有如下四种选择将
阅读全文
摘要:这个题分类是dp,想了一会没有想出来,就去看别人题解了。发现别人题解全是暴力枚举= =。复杂度超过 N^2,但可能是剪枝的作用,没有超时。思路:将所有点按坐标由小到大排序。两两枚举点p1,p2,并判断其中坐标较小的点p1是否是该路径上青蛙跳至的第一个点(假设在p1之前还有一点,则可以根据p1和p2的距离算出p1前一点的坐标,判断该坐标是否在麦田内,若不在则说明p1是青蛙跳至的第一个点)。判定p1前一点坐标时,我原以为由于所有点的坐标都是排好序的(从小到大),则p1前一点的坐标必然更小,因此判定它是否在麦田内时只需要判断是否坐标都大于0,并不需要判断是否超坐标上限。但这种思路是错误的。见下图。上
阅读全文
摘要:这道题我是看了别人的题解才做出来的。题意和题解分析见原文http://blog.csdn.net/lyy289065406/article/details/6698787这里写一下自己对题目的理解。1. 根据k的最大范围直接搜索n最后5位的方法是错误的,因为它并不能保证所求结果为最小。因为题目要求最后结果m要尽量小,而改变n的高位能够得到更小的值。k m尽量小。即最终得到的结果不一定是最小的,但一定是与n对应位置数字不相等个数最少的。这也决定了本题dfs的写法。3. 面对大量大数取模运算,利用mod[i][j]预处理(10^i)*j模k的值,节省了大量时间。这样在dfs的过程中,改变某一位后的
阅读全文
摘要:题意:由n个牧场,编号1到n。每个牧场有一头牛。现在在牧场x举办party,每头牛都去参加,然后再回到自己的牧场。牧场之间会有一些单向的路。每头牛都会让自己往返的路程最短。问所有牛当中最长的往返路程是多少。思路:n最多到1000,floyd肯定超时。可以这样做,把图中所有的边先存起来,然后第一次用dijkstra求出以x为源点到每个点的最短距离。该最短距离为每头牛回家时的最短距离。然后建个新的图,将之前存的边反向加入图中。如之前有条从5到8距离为2的路,则此时向图中添加的边为从8到5距离为2的边。这样再次以x为源点求到每个点的最短距离,将两者相加,就是每头牛往返的最短距离了。求其中的最大值即可
阅读全文
摘要:题意:有a个村庄,编号为1到a,有b个城堡,编号为a+1到a+b。现在超级玛丽在a+b处,他的家在1处。每条路是双向的,两端地点的编号以及路的长度都已给出。路的长度和通过所需时间相等。他有一双鞋子,可以使用k次,每次使用后最多可以跑过l的距离,且通过这段距离所需时间为0。使用鞋子时,必须从村庄或城堡开始,到村庄或者城堡结束。但是,城堡充满了陷阱,他如果中途遇见城堡,就必须停下来,且鞋子视为使用完了一次。问超级玛丽回家所需的最短时间。思路:用floyd算法先处理出任意两点间的最短距离(不用鞋子时)。另用一个二维数组来维护两点之间是否允许用鞋子直接传送。当两点最短距离不大于l且中间不经过城堡时,数
阅读全文
摘要:题意:给一个字符串,求该串最多由多少个相同的子串相接而成。思路:只要做过poj 1961之后,这道题就很简单了。poj 1961 详细题解传送门。假设字符串的长度为len,如果 len % (len - next[len])不为0,说明该字符串不能由其他更短的字符串反复相接而成,结果输出1,否则答案为len / (len - next[len])。 1 #include 2 #include 3 #define maxn 1000010 4 char s[maxn]; 5 int next[maxn]; 6 void get_next(char str[]) 7 { 8 next[0]...
阅读全文
摘要:题意:给一个长度为n的字符串,如果它长度为l(2 2 #define maxn 1000010 3 char str[maxn]; 4 int next[maxn], len; 5 void get_next() 6 { 7 next[0] = -1; 8 int i = 0; 9 int j = -1;10 while (i < len)11 {12 if (j == -1 || str[i] == str[j])13 {14 i++; j++;15 next[i] = ...
阅读全文
摘要:题意:有n只虫子,每次给出一对互为异性的虫子的编号,输出是否存在冲突。思路:用并查集,每次输入一对虫子后就先判定一下。如果两者父亲相同,则说明关系已确定,再看性别是否相同,如果相同则有冲突。否则就将两只虫子并入一个集合。而性别则是用一个gender数组来维护,每个虫子的gender的值为0或者1。0表示该虫子的性别与父亲结点的性别相同。1表示该虫子的性别与父亲结点的性别不同。这题和poj1703本质上是一样的。1703的题解请点传送门。另外还有一个疑惑,本题输入量巨大,我用输入加速后反而比用scanf要慢得多,弄不明白为什么。。有知道的大神欢迎来给解答一下。 1 #include 2 #def
阅读全文
摘要:题意:城市中有两个帮派,输入中有情报和询问。情报会告知哪两个人是对立帮派中的人。询问会问具体某两个人的关系。思路:并查集的应用。首先,将每一个情报中的两人加入并查集,在询问时先判断一下两人是否在一个集合中,如果是,则表明两个人的关系已知。本题还需要判断出两人是不是在同一帮派,这里用一个relation数组来维护每个人与根结点的关系。0表示该人与根节点为同一个帮派。1表示该人与根节点为对立帮派。并查集有两个基本操作:find——查找根节点, merge——合并两个集合。在合并两个集合时,其中一个集合的relation的值要发生变化。在这里只需要改变集合根节点的relation(改变的规则见代码中
阅读全文