usaco4.1

4.1.1 nugget beef

 最关键的是要知道拓展到何时停止,往后才都是连续序列。首先可以想到:

 如果给定的初始序列有不为1的公约数,那么必定无法产生连续的序列。

 另外,设拓展过程中出现了一段连续序列,其长度为l,如果l>=序列第一个元素(这是一个升序列),那么往后必定可以利用这第一个元素来产生连续的序列,此时可以停止拓展...这题数据范围不大,要知道这些就够了,大胆编程可以轻易过掉。但是,到底要拓展到何时才能确定往后都是连续的呢,盲目地拓展很没有安全感,说不定跑着跑着就挂掉了。

 可以先考虑初始序列只有2个元素的情况,设为a,b(a,b互素)。用现成的结论是:a,b互素时 ,丢潘图方程 ax+by=k 当k>=ab时,必有解,所以只要拓展到序列中最小的ab就行了,暴力点,直接把上限设置为256*256.

 当然只给出结论不能让人信服。

 尝试证明一下,不妨设a>b。k*b mod a(1<=k<=a)的余数不会重复,所以可以先构造出余数连续的序列,然后添加整数个a让它们的值也连续。

(若余数有重复就会有(k1-k2)*b mod a==0,这显然不成立 )

 现在可以放心拓展了,拓展可以用到前面3.1算humble number的技巧,维护一个索引......

 

4.1.2 fence rail

 这里用到一个改进dfs后的新算法,迭代加深搜索。我在这里犯了个错误,我以为按rail大小顺序来切,可以在有解得情况更快达到结果,而实际上不是,如何切割正是要搜索的东西,一块board可能同时从上切下来了大的rail和小的rail,按单调顺序反而在能得到解的情况搜不到。

 这里的每个剪枝都很重要,详见nocow

 我在二分答案的和剪枝的时候又犯了错误,二分法要特别注意边界处理,不然可能跳出不来。

 剪枝用的语句 if(board_sum - waste<sum_rail ) 写成if(board_sum - waste < sum_rail[deep]//剩余的大小)

 这样没错 但是剪枝效果远不如前一个。

4.1.3 fence loop

 用BFS把图遍历一次就可以求出最小周长,中间可以利用更新最小值来掐掉很多拓展。遍历过程中一旦遇到以前访问过的点,就说明已经走了一个回路,可以求周长了,所以访问顺序非常重要,开始没有注意,把走过的一条边当做了完成的回路,所以我后来增加了一个域来表示方向。

 

4.1.4 cyptcowgraphy

 全世界我都可以忘记,也不会忘记这群牛!!!!

 应该是可以直接构造出来的,官方的标程有400多行......还是只能用造hash判重的人品算法,无奈hash冲突不断...... 据说用stl的map可以很方便的处理...我要抓紧时间转c++了。

本文使用Blog_Backup未注册版本导出,请到soft.pt42.com注册。

你可能感兴趣的:(USACO)