比赛连接:
http://acm.hdu.edu.cn/diy/contest_show.php?cid=13254
这次的比赛,有几个特点:
(1)题目比较短,是方便大家记忆,继而在任何时候都可以思考,吃饭可以思考,走路可以思考,acm不考别的,就考思维;
(2)每道题几乎都出现了两次,是想告诉大家这么一个道理:暴力可以解题,但并不总是最好的,acm和c++的不同之处在于它不仅仅是靠循环构成的,还有智慧在里面,我们不要教大家编程,而是要教大家更好的编程。通过对比,大家一定可以发现,原来有更好的做
法,原来题目这么有趣。
好吧,废话少说,进入题解:
1001:
可以暴力,开个数组存F[0]...F[n],当然要对10取模。但有更好的做法。请看1002。
1002:
数据范围太大,显然不能暴力。有如下三种优化办法:
(1)由F[n]=3F[n-1]-2F[N-2], 推出F[n]-F[n-1]=2*(F[n-1]-F[n-2]),进而推出F[n]=2^n-1,容易 解得F[n]的最后一位。
(2)多列出几项,观察可得最后一位数字以4为周期循环再现,分别为1,3,7,5,1,3,7,5........
(3)直接用矩阵快速幂求的F[n],进而求得最后一位
第三种方法,看来有点傻,也非常麻烦。但是我希望大家都学一下(百度一下),毕竟如果有志于搞ACM,快速幂矩阵是必不可少的知识。
1003:
可以暴力,用O(n^2)的时间,对每个数字都访问一次,但有更好的办法。请看1004。
1004
(1)不妨排个序,调用系统的快速排序qsort(不懂的请百度学会),可在O(nlogn)的时间内完成,每个只需要比较前后相关元素。
(2)直接用异或(^),扫描一遍,相同元素会在异或符号下异或掉。希望可以通过这题,让大家认识到异或的作用。 若a==b,则a^b=0;即有1^1=0,0^0=1,1^0=1,0^1=1。
1005
可以暴力。
设sum[x],表示前x项之和,则sum[y]-sum[x]表示x+1到y项之和。从1到n分别枚举x,y,记录最大值if(max<sum[y]-sum[x])max=sum[y]-sum[x];max即为答案。
有更好的做法,参看1006。
1006
数据范围太大,显然不可暴力。
最大子串和,动态规划经典题。
设a[x]为序列元素,dp[x]为以x结束的最大和,则
for(int x=1;x<=n;x++)
if(dp[x]>0)
dp[x+1]=a[x+1]+dp[x];
else
dp[x+1]=a[x+1];
由以上关键代码求得以x+1为结尾位置的最大和。
且有dp[0]=0,为循环初界。
至此,O(n)算法得出。
1007
可以暴力。
直接统计每一个数前面的数有多少个小于它本身,O(n^2)复杂度。
可以优化,请看1008。、
1008
其实这题是防AK的,要想优化的话,有很多方法:线段树,树状数组,伸缩树,二叉检索树......
但都不是我讲得清楚的,真的想Ac得同学可以先去学习一下。
我出这题只是想让大家知道,acm和暴力编程的不同。
希望大家可以认真思考几天,尝试继续提交通过,具体代码过几天会给出。
1009
这题对于大一新生也比较难,是个广度优先搜索(bfs)过程。
不过在我看来,bfs是最容易实现的一个搜索算法(而且用处极大),不用递归,只要一个充当队列的数组就可以实现。
希望大家可以认真思考几天,尝试继续提交通过,具体代码过几天会给出。