UVa 11464 Even Parity

题意

请参考LRJ白书第一章例题7.

思路

大概是个带有机智成分的枚举。

为什么这么说,因为这道题的关键思路点就是发现只要知道第一行,就可以构造出整个数表,这样我们只要枚举第一行就可以解决问题,复杂度直接降低了一次幂。

代码

 

 

UVA 10881 Piotr's Ants

题意

请参考LRJ白书第一章例题5

思路

两个蚂蚁相遇会马上调换方向,从视觉上看其实相当于擦身而过(虽然两只蚂蚁的身份并没有交换)。就像在物理中,两个质量相等的小球发生完全弹性碰撞,交换速度。这里是本题第一个思路点。

无论在任何时候,第i只蚂蚁永远是第i只蚂蚁,因为上面也说了,只是视觉上的擦身,实际上蚂蚁又各自回去了。这是第二个思路点。在这个地方还有一个问题,那就是可能会以为仅仅是位置关系保持原来的顺序,其实方向关系也是保持原来的顺序的,这样就可以解决蚂蚁的最终状态的判定问题。

这样我们就有了解法:首先利用擦身而过的想法,求出最终所有蚂蚁的分布。然后利用标号守恒的想法,把终止状态和起始状态对应。

代码

 

LA 3708 Graveyard

题意

请参考LRJ白书第一章例题4.

思路

大概是构造题。

跟白书不太一样的解法,贪心地把两种方案的一个顶点对在一起,然后逐个检查,取两种方案的最小角度差,加在一起,就是答案。

代码

 

UVa 11300 Spreading the Wealth

题意

请参考LRJ白第一章例题3

思路

大概是个构造题。

解决的方法是把整个题转化成一个方程组,令每个人手里的初始金币数量为Ai(已知),送出数量Xi,受付数量Yi,最终每个人金币数量M(已知),这样得到由若干形如Ai-Xi+Yi=M方程组成的方程组,当所有方程形式一样时,考虑逐个联立消去未知量,最终得到了关于X1和Xi的若干等式(注意到Xi和Yi+1的相等关系),我们的目标是令Xi之和最小,我们把所有Xi加在一起,就得到了一个仅关于X1的和式。

这个和式的形式可以几何表示是求数轴上一个点,使得其与若干已知点距离之和最短,这个问题的解取在中位数,这样本问题就可以解决了。(中位数是解的想法在白书上有详细的证明,使用反证法)

综合来看,本体需要适当转化,数学变形,数形结合。

代码

 

UVa 11729 Commando War

题意

请参考《LRJ大礼包::白》第一章例题2

思路

大概是贪心。

只要交代了任务,部下自己就会给做完了,基于这样的题意我们就可以设计这样的一种贪心策略:优先考虑完成任务时间长的,这样交代完了之后就会有更多的时间可以一边交代任务一边有人完成任务,更有效率。

具体操作就是把完成任务时间从大到小排个序,然后顺着检查一遍。

这个策略的证明在白书上面有提供,大概的证明套路就是说明不用这个策略时得到的答案不会更优,在证明时分类讨论了两种情况。

代码

 

 

 

POJ 3646 The Dragon of Loowater

题意

请参考<LRJ大礼包::白>的第一章例题1.

思路

大概是贪心。因为骑士的能力=能砍多大=花多少钱,这样的话只要排个序,从最便宜的英雄开始检查,从小头开始砍,直到检查完最后一个英雄。

如果没砍死就是没解,否则一定是最优解,这个思维和Kruskal算法是一致的。

代码

 

Editoral for SCUT ICPC Team Qualification Round A

点按此处下载题面

PROBLEM A

很明显,双方最优策略是一直往前走,对手一直往前就能赢了,所以bx hao sui啊!

PROBLEM B

做这个题需要知道二项式定理,乘法逆元和等比数列求和,组合数取模。

    \[\sum_{i=1}^{n}(a^{i}+b^{i})^{k} = \sum_{i=1}^{n}\sum_{j=0}^{k} \binom{k}{j} a^{ij}b^{i(k-j)}=\sum_{j=0}^{k}\binom{k}{j} \sum_{i=1}^{n}q^{i}\]

    \[q = a ^ {j} b ^ {k-j}\]

后面就是等比数列的求和。

需要注意的是q=1的时候。

二项式系数可以用阶乘和逆元预处理,等比数列求和也可以用逆元求出来。复杂度O(Klog(N))。

PROBLEM C

这题求的是一个有向无环图的最小树形图。可以对每个点,选一个权值最小的入边加起来就是答案。

PROBLEM D

直接模拟统计出到最后时刻情怀值会受损多少。对于每个时间点,如果不能ak,则损害值增加tn-ti。最后总的损害值如果比原始情怀值小则just enjoy coding,否则fail to graduate。

PROBLEM E

PROBLEM F

PROBLEM G

 

PROBLEM H

对于每个数,我们需要满足的条件有两个:一个是各数位数字单调递减,第二个是这个数字满足被6整除。首先,如果直接枚举满足第二个条件的数,那么要枚举的数太多,复杂度太高。那么我们首先考虑满足第一个条件。各个数位的数字单调递减说明了各个数字不同(即每个数只能选一次),而数字只能在0-9这10个数选取(说明最多取10个数),且满足单调递减(说明对每组取的数,只有一个方案是符合的)。于是所有满足条件“各数位数字单调递减”的数字只有C(10, 1) + C(10, 2) + C(10, 3) + … + C(10, 9) + C(10, 10) = 2^10-1 = 1023。于是我们可以通过搜索的方法找到所有满足第一个条件的数,然后判断是否满足第二个条件。搜索的方法是先枚举高位,再枚举低位,每次枚举的数都得比高位的数小,直到没有数可以枚举(最小是0)结束。用递归可以解决。最后我们求出所有满足第一和第二个条件的数只有两百多个。注意最大的数会超出int的范围,所以我们可以用一个long long数组存下满足条件的数。接下来我们由于我们最多只有20组数据,所以我们可以判断每个合法的数是否小于或等于输入数据。

主要部分代码如下:

 

PROBLEM I

 

PROBLEM J

把下标乘上1000得到一个递推式子,

BX(n) = BX(n – 1000) + BX(n – 1234)。

答案就是BX(n*1000)

Author Information

ABCJ : doubility(czk)

DH : ConquererV587(kbx)

GI: Xdynix(rxy)

动态规划初步

[toc]

什么是动态规划

  • 动态规划是一种方法,或者说思想,它并不是某种特定算法。
  • 动态规划方法的通俗解释:将原来比较复杂的问题分解为若干比较简单的子问题,将这些子问题逐个解决,并存储这些子问题的答案,原来的问题的答案将会从这些分解了的子问题的答案中导出。等到下一次遇到了相同的子问题时,我们只是提取出事前存储的问题的答案,而不是重新做一次计算。
  • 对上面通俗解释的解释:无论是原问题,还是子问题,都是问题,我们拿到一个问题,给他分解为若干子问题,那么接下来我们如何解决子问题?那就是把每个子问题当成原问题再度分解,得到子问题的子问题,然后为了解决这些“子问题的子问题”,我们再度分解。。。直到最终我们得到了已经无法再分的“原子问题”,我们假定原子问题是可以很好地被解决的,那么我们理论上只要解决的全部的原子问题,再回推,就可以解决掉全部子问题,最终解决最根本的问题,也就是我们拿到的问题。而动态规划方法体现在我们加速这个过程上,在问题的分解过程中,我们可能会遇到重复的情况,如果我们对这些重复的情况调用之前计算好的答案,就不用再次深入分解问题,这样能大大加快整个求解进程。
  • 动态规划的关键字:递推、记忆化、状态转移

状态

什么是状态

  • 字面含义:物质系统所处的状况。
  • 我们这里所说的状态是一种抽象观念。
  • 在动态规划的设计上,一个“状态”,表达的是在某个情形下的子问题。
  • 在动态规划的操作上,状态最终表现为一个又一个的值,也就是在某个特定情形下的子问题的答案。

状态转移

  • 基于当前状态和其他输入,移动到其他状态。
  • 说人话:某个东西现在是某个样子的,然后我对他动了些手脚,这个东西变成了另外一幅样子。
  • 当前状态能不能转移到当前状态?可以
  • 如何表达状态转移?
    • 状态转移方程(你可以列个公式)
    • 状态转移图(你可以把状态形象化为点,把转移条件形象化为边)
    • 状态转移表(你听说过函数表吗?虽然没怎么用过但这是初中内容。)

那么状态和动态规划有什么关系?

上面说到了,在动态规划里的“状态”表达的是“子问题”,前面也说了,动态规划整体来看是一个操作子问题的方法,这样我们也可以说动态规划是一个操作状态的方法。在动态规划过程中,我们分解当前状态,得到子状态,处理子状态,记忆子状态,最终处理好全部需要处理的状态,从所有状态中挑出合适的、我们需要的状态来代表最终答案。

用动态规划解决问题

必要条件

不是所有的问题都能用动态规划解决,能够使用动态规划方法解决的问题必须满足以下两个基本性质:

  • 对于一个问题,如果它取得了最优解,那么这个问题所能分解出来的所有子问题的解也是最优的,这个性质称为最优子问题/最优子结构
  • 如果我们已经解决了一些问题,那么当我们解决其他问题的时候,已经解决的问题的答案必须不能受新解决的问题影响。也就是说某个状态之后的过程不可以影响之前的状态。这一性质,称为无后效性

分治?

聪明的你发现了,分治法不也是把当前问题分解为小一点的问题直到不能再分,然后解决原子问题回推得到根问题的答案吗?分治和动态规划有什么区别?

适用于用动态规划法求解的问题,分解后的子问题往往不是独立的,在之后的求解过程中会用到之前已经解决的问题的答案。

上面说过了,动态规划过程中每个子问题的答案将会被保存以避免重复计算,这里才是我们高速解决问题的原因。因此我们有下面这种说法:

使用动态规划有意义的条件

  • 子问题之间不是独立的,一个子问题在之后的求解过程中可能会被多次使用到。这个性质称为重叠子问题
  • 需要注意重叠子问题并不是动态规划适用的必要条件,但是如果没有这个性质,使用动态规划并没有意义。

操作步骤

我们使用动态规划方法解决问题时,一般按照以下思维和操作程序:

  • 分析问题:判定其是否能且有意义使用动态规划。
  • 再度分析:找出将问题分解的方法,将分解后的问题合并的方法,确定原子问题的位置(即边界条件)。
  • 定义状态:确定每个状态对应的问题是什么,答案表示什么,携带的情形是什么。
  • 处理状态:递推 and/or 记忆化。
  • 选择答案:从处理好的状态中选择我们需要的合适的状态作出最终答案。

关键点

  • 状态设计
  • 转移方程
  • 初始化
  • 二次优化(本文不讨论)

如果把目光放长远一点

  • 动态规划方法解决了一个问题,但这很可能并不是你要解决的问题的全部。
  • 递推可以叫动态规划吗?我认为可以,你可以看成每个问题只能分解出一个子问题,虽然感觉上有一点奇怪,而且你要注意到递推过程中并没有重叠子问题,即使你管他叫动态规划,那也是没啥意义的动态规划。
  • 开一下脑洞:你用一种动态规划方法分解出来的原子问题需要另外一种动态规划方法解决?你现在动态规划解决的问题其实只是另一个问题的模块?想想就好了,高中生啥都干的出来。

一些经典且简单的模型

关于Fibonacci

广义/系数Fibonacci

首先要说的是,Fibonacci数列中,最有分量的一句话其实是f_i = f_{i-1} + f_{i-2}f_1f_2的值并不重要,所以我们在这里可以推广Fibonacci数列的含义为只要有这样的递推就可以称为(广义)Fibonacci数列。

我们都知道Fibonacci数列,要想快速应付多次查询我们可以事前预处理,要想快速应付一次巨大的查询我们可以使用矩阵快速幂。那么如果我给出下面的问题呢?

Given f_1 = a,f_2 = b,f_i = f_{i-1} + f_{i-2} for every f >= 3,for each query you will get 3 numbers a,b,c,you have to output f_c in condition of given a and b.

这个问题意外的简单,仔细观察我们就发现了,对于给出的这个数列的每一项,a的系数实际上是f_1=1,f_2=0的Fibonacci数列,b的系数实际上是f_1=0,f_2=1的Fibonacci数列,所以接下来怎么操作想必大家都很清楚。

Fibonacci的前缀和?

是的,也是Fibonacci数列。

前两项的作用

前两项事实上决定了整个Fibonacci数列,因此只要知道前两项,就相当于知道了整个Fibonacci数列。

数字三角形

问题

POJ 1163 The Triangle

解法

我们令A[i][j]表示金字塔从上往下数第i行第j个数。

我们令dp[i][j]表示从金字塔从上往下数第i行第j个数。

对于金字塔上每一个点,我们假定已经计算出了从这个点左下方出发走完金字塔的最优解和右下方走完金字塔的最优解,那么从这个点走完金子塔的最优解已经是从左下方或右下方走完这两个可能性中最优的那个,再加上当前这个点的数值,即:

dp[i][j] = best(dp[i+1][j],dp[i+1][j+1]) + A[i][j]

对于最后一行,因为已经是底部,所以dp[i][j] = A[i][j]

最后,我们需要的答案是从塔尖走完整个金字塔的最优解,即dp[1][1]。

问题解决。

背包问题

背包问题九讲

我们只关心这些内容:

  • 01背包
  • 完全背包
  • 多重背包
  • 滚动数组

最长上升子序列

问题

POJ 2533 Longest Ordered Subsequence

解法

令A[i]表示原数列第i位数。

令dp[i]表示检查到原数列第i位(且最后一位就是第i位)时的最长公共子序列长度。

那么对于没有解决的dp[i],我们依次检查所有在第j位之前的数,假设检查到了第j位:

  • 如果A[j] < A[i],那么我们可以选择在j位表示的最长上升子序列后面添附第i位数,这样得到了一种可能的dp[i]=dp[j]+1
  • 否则,我们只能选择放弃之前的结果,这样得到了一种可能的dp[i]=1
  • 我们综合所有可能的dp[i],选出最大的那个,保存

对于第1位,显然只有它自己一个构成了一个上升序列,因此dp[1] = 1。

这样我们完成了状态转移,最终结果就是dp数组中的最大值.

我们只关心O(n^2)的解法(还有一种O(nlogn)的解法)。

Editorial/Tutorial for TIC Weekly 2

Summary

本次比赛总体难度:BASIC

问题难度分布:
BASIC 4题 A C G I
MODERATE 3题 D E F
ADVANCED 2题 B H
HARD 1题 J

比赛的参加人数过少,所以无法从数据中观测到太多有价值的信息,不过大家的实现能力和读题的耐性还有待提高是一定的。

恭喜Winner:何|浩宁。

本次标题梗:同人社团Alstroemeria Records的音乐作品,下面的标题都是可以戳进去的。

A – Against, Perfect Cherry Blossom.

Vocal版来自专辑Double Counterpoint 是Alstroemeria Records与Syrufit的合作专辑

原始问题:URAL 2066 Simple Expression

难度:BASIC

知识点:暴力枚举 基本实现

详细题解与AC代码:请点按此处

B – Bad Apple!!

传说曲Bad Apple!!(fect. nomico)来源于专辑Lovelight

原始问题:UVA 10054 The Necklace

难度:ADVANCED

知识点:图论 欧拉回路

详细题解与AC代码:请点按此处

C – Crystallize Silver

来自专辑BLUE NOTE Original Score: クリスタライズシルバー 東方妖々夢

原始问题:CodeForces 583A Asphalting Roads

难度:BASIC

知识点:基本实现 模拟

详细题解与AC代码:请点按此处

 

 

 

D – Dark Road

来自专辑Harmony Original Score: 厄神様の通り道 東方風神録

原始问题:UVA 12955 Factorial

难度:MODERATE

知识点:贪心

详细题解与AC代码:请点按此处

E – End Of Daylight

个人比较喜欢的Vocal版本来自专辑Fragment Reactions 早期专辑亦有其他Arrange

原始问题:UVA 12946 Peanoland contacting Gaussland

难度:MODERATE

知识点:模拟 STL

详细题解与AC代码:请点按此处

F – Fragment Reaction

Fragment Reaction 专辑同名曲。

原始问题:HDU 1241 Oil Deposits

难度:MODERATE

知识点:DFS

详细题解与AC代码:请点按此处

G – Graphical Scenery

外援Ryo Ohnuki的原创曲 来自专辑DANCEFLOOR COMBAT

原始问题:Codeforces 515B Drazil and His Happy Friends

难度:BASIC

知识点:模拟 暴力 简单实现 GCD

详细题解与AC代码:请点按此处

H – How Is Your Eyes Crazy?

来自专辑Lovelight

原始问题:Codeforces 589A Email Aliases

难度:ADVANCED

知识点:STL 模拟

详细题解与AC代码:请点按此处

I – Imperishable Night

来自专辑Double Counterpart

原始问题:CodeForces 236A Boy or Girl

难度:BASIC

知识点:基本实现

详细题解与AC代码:请点按此处

J – Japanize Dream

AR社的首张东方同人专辑

原始问题:CodeForces 3C Tic-tac-toe

难度:HARD

知识点:模拟

详细题解与AC代码:请点按此处

Scroll to top