Wednesday, April 18, 2007 12:13:23 PM
Analysis, Programs
几周前终于做完了USACO Training的全部题目,感觉收获极丰,便有将这些题目做一总结的想法。
写时根据算法对题目进行分类,只求使自己从USACO中得到的知识条理化、系统化,并不求能给他人什么教诲。
笔耕数日,终于约一周前写完全部四篇初稿。又经过近日的几度增添润色和几位好友的帮忙校对,终能在省选的前夕发布所谓“正式版”。
本人自知水平有限,文中断少珠玑之言,而若此“心得”能为你的OI征程有所裨益,也不枉本人几周来的一番心血。
URL]
Thursday, April 5, 2007 11:39:33 AM
Congratulations! You have finished all available material.
Thursday, April 5, 2007 2:03:35 AM
Analysis, Programs
刚开始看到这题时,真的是一点头绪都没有呢。不得已寻觅各种题解……结果众牛异口同声地说:离散化+线段树。于是便开始写……写着写着……觉得真的麻烦死了。又看了USACO官方的Analysis。很惊异于那个程序的长度和编程复杂度(好短啊……)。不过我怎么都觉得这个程序不应该AC的,因为它的时间复杂度大约为O(20000*N)。(我知道……这种写法是错误的。你可以说这是O(N),但是它在n次循环里每次都要扫描一个长度为20000的数组……这就导致了超时。)
那个程序真的需要将两个数组拷贝来拷贝去吗?真的需要每次都扫描整个数组吗?不是的!只需要在每次增值或减值时判断数组的这个元素是否由零变一或由一变零就可以了!这样就大大降低了实际的耗时。(虽然原则上来说没有降低渐进时间复杂度。)
最后的程序只有83行哦!但是却能做到最后一个数据0.204s的效果。太神奇了……
picture.cpp
Wednesday, April 4, 2007 7:31:16 AM
Analysis, Programs
TASK: charrec
LANG: C++
Compiling...
Compile: OK
Executing...
Test 1: TEST OK [0.036 secs]
Test 2: TEST OK [0.036 secs]
Test 3: TEST OK [0.068 secs]
Test 4: TEST OK [0.128 secs]
Test 5: TEST OK [0.304 secs]
Test 6: TEST OK [0.416 secs]
Test 7: TEST OK [0.592 secs]
Test 8: TEST OK [0.592 secs]
Test 9: TEST OK [0.628 secs]
All tests OK.
YOUR PROGRAM ('charrec') WORKED FIRST TIME! That's fantastic
-- and a rare thing. Please accept these special automated
congratulations.
我只能说……这太神奇了。我也没想到。
虽然基本方法是DP谁都能看出来,但这题看上去真的很麻烦,不过仔细的划分模块以后就可以写得很有条理。
charrec.cpp
Tuesday, April 3, 2007 11:58:56 PM
Analysis, Programs
剪枝:
1.第1行第1列都是1-N。
2.最后一行不用搜,一定有解。
3.前两行可以当成置换群用hash保存答案。
(Analysis里面那个剪枝还没看懂……)
1latin.cpp
Tuesday, April 3, 2007 12:23:30 PM
Programs, Analysis
这题我是用纯DP过的哦!
坦白地说,这题是这几天做出的题里面给我最大快感的一道。感觉真是学到了新东西。这种DP不仅要求出得数,还要方案。而且还要字典序最小的一个方案。所以在更新解的过程中若发现当前解与新解的值相同,就必须要比较两个解的方案的字典序。
milk4.cpp
Tuesday, April 3, 2007 9:17:46 AM
Analysis
算法是矩形切割。要配合链表的操作。(似乎必须写双链表?)
这是我的程序中“模块化”和“抽象层次”做得比较满意的一点。虽然没有用OO。但是将链表的操作抽象成几个函数,将输入数据的处理抽象成几个函数……层次上非常清晰。我对这程序非常满意。
window.cpp
Tuesday, April 3, 2007 8:10:36 AM
Analysis, Programs
方法是这样的:
首先,用你喜欢的方法求出强连通子图。然后第一个问题的解就是没有入边的强连通子图的个数,第二个问题的解就是没有出边和没有入边的强连通子图的数目中较大的一个。
schlnet.cpp
Tuesday, April 3, 2007 3:11:20 AM
Analysis, Programs
通过这题要掌握二维离散区间中的搜索方法,就是不断调整,同时缩小调整的范围。这显然可以推广到更高的维度。但每次调整的次数应有一个上限,否则就会出问题(在USACO的评测机上会超时,似乎是死循环,而在我的电脑上就不会,所以说for(;;)还是要慎之又慎啊!)。
fence3.cpp
Monday, April 2, 2007 12:53:31 PM
Analysis, Programs
裸凸包……graham-scan。用折腾了半个下午加半个晚上。不断地出低级错误。太累了……不多说什么了。
fc.cpp
Monday, April 2, 2007 2:42:58 AM
Analysis, Programs
很精妙的一个DP。
v[k][j]表示以i和j开头的最长主题。
v[k][j]=s[j+1]-s[k+1]==s[j]-s[k]?v[k+1][k+1]+1:1;
如何减少储存空间?注意状态间的依赖性。按照枚举i和j的距离来求值。我想你应该明白我的意思。
第一次提交没过是因为没看见is at least five notes long这一句。
theme.cpp
Monday, April 2, 2007 1:54:57 AM
没什么值得高兴的,还有19道题呢。
本周内至少做完Chapter5。
Monday, April 2, 2007 12:57:42 AM
Programs, Analysis
这是最小割模型的经典应用。最小割的数值自然可以根据定理得出,但如何得出最小割的边呢?我采用的是北极天南星题解中的贪心法。我感觉这个应该有反例——不该这么简单。但是反正AC了。这种方法的确应该记住。
(另:一开始错误的把这题当成最小费用流了……汗……)
milk6.cpp4.7:那个贪心法是正确的。
Sunday, April 1, 2007 9:13:41 AM
Programs, Analysis
据说Matrix67的USACO征程就是在这里卡住了,所以我做好了像cryptcow一样打持久战的准备。没想到……今天一天就搞定了。而且……最大的数据不超过0.1s,呵呵。太有成就感了!
说一下比较特别的地方:
1.搜索顺序是先对角线、再边缘、再中间。
2.主要的剪枝依靠V数组,它能告诉你哪怕不完整的一行一列有没有可能是素数。
3.将“两边两数已确定且没有0”和“两边两数已确定且仅有1379组成”的东西建一张表,在搜索边缘的时候可以用到。
总结一下就是:用空间换时间。(这话好俗啊……)
prime3.cpp
Saturday, March 31, 2007 4:06:48 AM
Programs, Analysis
做这题前我看了北极天南星的题解,但是按照那个编出来的程序却不对(应该是我没理解的缘故),自己想了一个不同的方法(似乎比那个麻烦),但还是对了。
高精运算的确是个不难的东西,特别是在C++里,我先用int编好程序确认了正确性以后直接把声明处的int改成BigNum就行了。
buylow.cpp
Saturday, March 31, 2007 2:54:14 AM
Programs, Analysis
由于这题的数据规模实在是太小了……所以几乎只要是多项式的算法都能过……汗……我写的就是O(n^3)的,可还是最大的数据0.004……不过显然有更好的方法,看看别人的标程吧。
race3.cpp
Friday, March 30, 2007 11:39:16 PM
Analysis, Programs
这题实在太有意思了!第一问当然easy,关键是第二问。我们如果从“策略”的角度来想,也就是说每一个从A出来的东西要放到哪个B里,会完全无从下手。
正确的方法是:将两问分开来,也就是先假设两个任务是彼此独立的,都当第一问来求。然后利用单调性,把a[k]和b[n-1-k]配对。over。
job.cpp
Friday, March 30, 2007 11:36:51 AM
Analysis, Programs
懒了一下,把上题的flow直接复制过来了……不过最后一个数据竟然用0.8xx秒?汗……似乎是我的网络流编得很不到家。(采用邻接矩阵,没有对稀疏图作优化。)
明天再写Hungary。
stall4.cpp3.31:
针对稀疏图进行了优化的网络流(最大的数据0.068s):
stall4(1).cpp使用Hungary算法的程序,加了一点点优化(最大的数据0.004s):
stall4.hungary.cpp
Wednesday, March 28, 2007 5:35:16 AM
Analysis, Programs
使用的剪枝:
1.前缀后缀的判断。
2.第一个特殊字符必须是C,最后一个特殊字符必须是W。
3.搜索过程中所有COW之间的片断都必须是原文本的子串。(使用Prefix Tree实现)
4.乱写的hash函数判重,不处理冲突。
使用的技巧:
1.使用链表保存字符串,可以是每次变换的时间为O(1)。
2.枚举COW的组合是应先找到O,然后从前面找C,从O后面找W。
起初迟迟不能AC的原因:
对于每次字符串的变换事实上需要分四种情况讨论,否则就会破坏链表造成死循环。
cryptcow.cpp
Friday, March 2, 2007 9:49:11 AM
Programs, Analysis
搜索题。比较典型的迭代深搜。里面的优化也是比较典型的。我主要用的优化有:
1. 二分答案。
2. 对boards和rails都进行排序。
3. 出现重复的board或rail时可剪枝。
4. 事先试图缩小答案的上限。
5. 每次枚举用那个board放当前的rail时都先寻找有没有和现在的rail完全相同的,如果找到就不再尝试其它board。
fence8.cpp
Saturday, December 23, 2006 11:37:39 AM
Analysis, Programs
一道恶心的计算几何题……计算几何的特点就是可能会出现很多烦人的特殊情况。不过,在我天才的灵感推动下,我成功的尽用了两次提交救过了这道题(第一次提交甚至连判断非规范相交的代码都没有写,而且只有最后一个点没过)。我创造性地发明和使用了所谓的“shake方法”(欲知其详,请研究我程序中的shake函数),这使得特殊情况、刁难人的数据都不在话下一扫而光啦!
fence4.cpp
Thursday, December 21, 2006 8:03:40 AM
Programs, Analysis
我做的第一道几何题……不过这个不算计算几何,应该算作解析几何吧。那个为了排除恰在线上的点而加上一个小差量再取整的方法是我原创的哦!
fence9.cpp
Thursday, December 21, 2006 5:50:06 AM
Analysis, Programs
这是一个经典的DP题。第一次提交时第8个数据WA……原因是把一个字母写错了:i写成了t……宛如NOIP的场景重现啊……太失败了。以后对于DP题在提交之前要再把solve程序和方程对照一下,看看solve程序是否重视的体现了方程……
rockers.cpp
Monday, December 18, 2006 4:52:17 AM
Analysis, Programs
我显然把这道题想麻烦了:构图,每种购买商品的组合是一个顶点,每种打折方式是一条边,然后就SPFA……可是显然不用这么麻烦,可以DP的……以后有空了再用DP写个程序。
shopping.cpp
1 2 3 Next »