May 25

国软比赛总结 不指定

felix021 @ 2009-5-25 01:58 [IT » 程序设计] 评论(1) , 引用(0) , 阅读(6197) | Via 本站原创
很纠结地最后可以参加这个比赛了,但是这个比赛只能两个人参加,于是BFS只能拆散了。
Sandy和Boluor组队,然后我另外去找了Eire组成新队,队名70km  :D

12点左右就到了机房,结果LCY说对外通知是12:30入场>_<|| 郁闷。
然后随便找一台机器测试了一会儿,到大约12点40的时候被安排坐到team30的位置(可是我们是team51=.=)
花了一点时间把vimrc先大致敲了一点进去,和eire讲了一点vim的基本操作,敲了一个model.cpp

1点多一点点开始比赛,8道题目,可是国软这次这么小气,两个人才一份题目,orz。
于是把题目拆开,Felix负责ABCD,Eire负责EFGH。
还好是中文,看完比较快,Eire说后面四道题目貌似没有直接可以写的
然后我看到B是一个简单的BFS,C是一个更简单的模拟水题
于是直接上去敲C,结果很快就WA了,检查了一下,发现一个小错误,Submit,又WA,超郁闷。

打印代码一边检查,然后Eire看H题,我和他讨论了一下,刚开始想到记忆化搜索
但是发现不对,没有高精肯定要溢出,高精效率又太低。
于是列出一个不太严谨的式子:如果把n拆成x份,那么最后的结果是x^(n/x)(忽略小数)
然后大致证明了3是最划算的(我居然忘了怎么求导T_T 还好Eire还记得。。。)
然后又大致觉得如果是4就应该拆成2 * 2
于是顺着这个不严格证明得出的思路写代码。

其间Felix改了一下C题,又WA,检查代码发现多了一个测试的printf T_T,注释,提交,AC@35min
一个简单的C题被我搞出3个WA。。。罪人啊。。。。

很快Eire根据那个"证明"结果写出了代码,提交,1AC@42。振奋。

然后Felix看B题的BFS应该很简单,虽然Eire有点担心,但是还是毅然决然地开题
写完以后测试发现不太对,打印代码一边晾去,由Eire开始写他想得已经差不多的G题
其间Eire又转去细想,而Felix在打印的代码上面发现了几处错误
改正以后样例基本OK了,然后是最后一个不对
自己看了一下样例,发现是样例错了,于是问judge。
结果被告知出题人kid正在地大回途中,waiting。。。

于是Eire继续G题,由于roman 2 arabic的函数写得很好,然后用一个struct+stable_sort,1AC@114min
这个时候开始网络变得非常垃圾,点一个Refresh就能把PC^2卡死,超郁闷。

还好等了不是太久kid回来了,原来是他把6写成5了,不好改题目,于是就把数据改了。
然后提交之,发现TLE了,超囧。
检查了一下,发现在BFS的循环里面有错,队尾指针在某个情况下不会改变(以前没遇到过),于是很囧地进入死循环TLE
修改了以后检查了一遍,又发现一些其他的错误,一并改之,提交,WA@130+min T_T
很郁闷很郁闷地继续检查,大概160min发现原来是存名字的map在每一个case之前没有clear,超囧。
又提交一次,还是WA!郁闷啊郁闷啊郁闷。
纠结了很久,大概30min以后问了maner是不是最后一个case后面不需要再加\n
maner说,大概是。。。于是改之,提交,终于AC@196min...

剩下的四道题目和Eire讨论了一下:
A题是一个枚举+二维DP的问题,Felix能想出这个框架,但是实在是不会写DP,无奈放弃
D题状似计算几何,但是细看其实不然。Felix也想出了应用容斥原理的算法基本框架,就是不会写T_T
E题可见边——Eire很后悔地说没有带上图形学的书。。。
F题奇怪的比赛——完全没有思路,嗯。

此时70km@Rank2,仅次于momo+feli。
但是后面好几个队伍都出了3题甚至4题,估计很快就能超过我们,郁闷
更郁闷的是LCY同志宣布:由于比赛过程中网络状况比较差,比赛延长半个小时
于是我深情地拉着LCY的手说:我恨你T_T

由于最后一个半小时都没有题目可以做,于是Eire在5点多一些就先跑路了
Felix非常无聊地水了一下D题,毫无意外地TLE,于是也不再继续写了。。。。

——

最后非常意外地70km还是留在Rank2的位置。究其原因,主要有这么几点:

首先,因为从地大回来的队伍不仅推迟一个小时才开始做题,而且都太累了——毕竟写了一天的代码啊,此乃侥幸。

其次,做题策略把握得比较好——
  a) 看题,我们把所有的题目都快速扫过去,没有一看到简单的就急于做出来,
      因此在整个比赛的过程中基本上是按照从简单到难的顺序做出来,这个还是比较划算的
  b) 比赛的过程中时间安排得好。一旦觉得自己会陷入僵局的时候就打印代码换人写
      事实上确实是,在纸上看代码很容易找到代码的错误,并且往往一次能找出不止个一并改好
  c) 把自己的想法适当地和队友讨论,这样能让自己明确自己的思路,找到自己可能存在的问题,
      同时如果自己存在问题,也可以借助队友的局外人身份找出(旁观者清啊!)

再次,河蟹的队伍气氛也很重要。整个比赛过程中非常开心,无论是卡题还是AC还是WA还是TLE(其实后两个结果都是Felix的贡献T_T),都可以笑得很happy,一点沉重的气氛都没有,我觉得这对队伍比赛时的状态有非常积极的作用,让我想起的去年暑假集训的Matrix76队,气氛一向都是非常河蟹。

此外,发现自己的基础还有很大一部分不扎实,主要体现在:
1. 简单的DP不会写.....
2. 容斥原理不会写.....
3. 算法流程没有完全想清楚就开始码字.....
4. 一个BFS能写出好几个错误,边写编改.....
5. 居然能挂在初始化上面,无语啊无语啊无语。。。

以上,OVER,特别感谢队友Eire同学,嗯。
May 24

软考,RP之。 不指定

felix021 @ 2009-5-24 00:36 [IT » 其他] 评论(1) , 引用(0) , 阅读(6554) | Via 本站原创
虽然在报名截止之前匆匆交了120,还花了50多买了一本教程,但是后来一直没有抽时间好好复习,以至于说过n次不想考了。
昨晚在看了半晚上《李彦宏的百度世界》以后,终于毅然决然地捧起了《软件设计师教程》——毕竟花了50多,不看完太浪费了。
于是花了大概三四个小时翻完了。
然后打开玉哥发到班群邮件里面的那个历年试题.chm,看了2006年5月的题目(因为有答案),3点,睡觉

早上7点30撑起眼皮爬起床,8点20在华师门口和璐希、佳璐汇合,然后佳璐带路到9301去。好困。
8点45左右入场,9点开考。
监考的似乎相当业余,不检查是否有枪手,发卷子和答题卡也很随意,导致我差点被忽略掉。。
题目其实都蛮简单,大约1个小时多一点做完,涂答题卡,检查是否涂错,然后大概点了一下
大概有十几题是不确定是否能作对的,大概有50~55题是比较有把握的,因此估分是55~60。
p.s. 总共75题,每题1分,据说一般45就算过。
交卷,10:15。
监考人问:草稿纸呢?
答:你们有发么?
监考人:...

10:30回到宿舍,然后打开那个chm,把05年下半年的下午题也看了一遍。
12点出去吃个午饭,回来睡午觉。1点07被电话吵醒,郁闷。继续眯,1点20起床。然后走到考场。

下午的题目更简单了。
前三题是DFD,数据库,UML,虽然对UML不熟,但是瞎蒙总能蒙不少分数的。
第四题是伪代码描述FLOYD的填空,超简单。
第5,6,7分别是C/C++/JAVA的填空,三选一。
第5题是用C写的二叉树非递归中序遍历,很简单,直接做了。
检查一遍,交卷,15:00。
估摸着应该也是在55~60分把。
p.s. 总共答出5题,每题15分,一般也是45算过。

看来软考是混过去了。
回想一下觉得其实考题不难,大部分都是平时课程的内容,综合到一块而已。
May 20

新进展:init_task 不指定

felix021 @ 2009-5-20 16:35 [IT » 操作系统] 评论(1) , 引用(0) , 阅读(8579) | Via 本站原创
XenLab项目里我这一块有了新进展:从System.map里面找到了init_task的虚拟地址。

简而言之,init_task就是linux的第一个进程,在载入init以后,它就进入一个无限循环,然后就变成传说中的idle进程。
更详细的内容参考《深入理解Linux内核》等相关资料。

当然,init_task的地址本来是不用费心去找的,如果你写一个内核模块,这个符号是可以直接引用的:
struct task_struct *task = &init_task;

但是我的目标是:从“Linux外”找到这个init_task的地址
因为我是要从Xen虚拟机的Dom0(类似宿主机的概念)去入侵DomU(类似客户机的概念)
找到init_task以后,我们就可以遍历Linux中的所有进程,然后就可以做一些ooxx的事情了。

因为宿主机是无法直接调用客户机的API,自然无法通过上述方式获得init_task地址。
本来是想通过某种方式直接从DomU中找出这个地址,但是毫无头绪
后来发现System.map可以挖出这个地址,虽然这个方法很挫,但是起码可以进行下一步的动作了。
May 20

24点 不指定

felix021 @ 2009-5-20 02:08 [IT » 程序设计] 评论(3) , 引用(0) , 阅读(7320) | Via 本站原创
本文包含一个很挫的算法和一个很赞的算法
-----------------------
24点是一个足够古老的游戏了:
给出四个一位数(可能重复),使用加减乘除和括号将这四个数字整合成一个算式,使得算式的结果等于24。
当然,不是所有的四个一位数都可以组合成24的,比如1,1,1,1显然就不能。
有两个经典的组合是 1, 5, 5, 5 和 3, 3, 8, 8 —— 你可以找出有效解吗?

对于任意给出的四个一位数,如果不考虑重复的情况(比如1,5,5,5,把三个5当成不同的数字)
那么可以算出,可能的算式有 (4*3*2*1) * (1*2+1*1+2*1) * (4 * 4 * 4)  = 7680种。
这么大的数字用人脑去算是很不合理的,所以应该写一个程序来处理,嗯。
(中间的 1 * 2 + 1 * 1 + 2 * 1是什么?——下面再说)

这个程序的实现我大一的时候曾经想过,但是那时候对语言掌握都很差,更别说写出具体的回溯等算法来实现。
昨天又想到这个问题,于是拖了这么久,终于在今天把代码写出来了(一题两年出,一跑就郁闷)。
May 18
网上可以搜到很多相关的资料,这里不具体说了,
大致就是,定义struct/class的时候 编译器会把其中的每个成员的存储位置对齐
对齐原则一般是和该成员大小一致,比如int的就从%4=0的地址开始存储,多余的空间就编译器随便填充了。
然后struct还要填充,直到整个struct的大小是最大成员大小的倍数(VC6.0)——为什么呢?
Felix觉得这样是为了保证连续存储的时候下一个struct的最大成员也是对齐的。
此外,编译器还会对struct的存储地址进行对齐。

我实际测试了一下,我发现32bit的gcc在对struct进行填充的时候
如果某成员的大小大于4Bytes(long long, double)的时候,实际上是以4字节对齐的。

如果在程序中指定了
#pragma pack(n)
那么对齐的时候就会把元素的大小和n进行比较,取较小的那个来对齐。

此外:
#pragma pack(push)
#program pack(pop)
可以成对使用,用来保存(push)当前的n和取出(pop)之前的n——当然,这是在编译过程中处理的。

下面是我的一段测试程序:
May 16

字符串的Hash 不指定

felix021 @ 2009-5-16 23:11 [IT » 程序设计] 评论(1) , 引用(0) , 阅读(7354) | Via 本站原创
早上参加了腾讯的笔试,做完以后自我感觉良好,但是后来和sandy讨论了一下,发现还是挫了,因为没用上Hash。
于是中午回去狠查了一些资料,看到了一点东西,充实了些。

看到一些字符串的Hash函数,想测试一下它们的实际性能
于是写了个程序来生成5w个字符串
用不同的hash函数计算hash值模9793(随便写的一个数字)
然后再用 sort 和 uniq 看了一下结果,发现 sdbmhash 是最好的, jshash其次,也很不错
然而很意外的是 elfhash 的性能则相当差,完全达不到可用的标准
——在对5w个数进行hash以后得到的结果里面,居然有700多个0和400多个1。

下面贴一些代码:

gen_data.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char tbl[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+=-?><:';,./][{}\\\"";

int main(){
    char s[1024];
    int i, l, m = strlen(tbl), j;
    srand(732984);
    freopen("str.txt", "w", stdout);
    for (i = 0; i < 50000; ++i){
        l = rand() % 100 + 1;
        for (j = 0; j < l; ++j)
            s[j] = tbl[rand() % m];
        s[j] = 0;
        printf("%s\n", s);
    }
    return 0;
}


hash.cpp
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;

unsigned int elfhash(char *s){
    int hash = 0, x = 0;
    while (*s){
        hash = (hash << 4) + (*s++);
        if(((x = hash) & 0xf0000000l) != 0){
            hash ^= (x >> 24);
            hash &= x;
        }
    }
    return hash & 0x7fffffffl;
}

unsigned int jshash(char *s){
    int hash = 1315423911;
    while (*s){
        hash ^= (hash << 5) + *s++ + (hash >> 2);
    }
    return (hash & 0x7fffffffl);
}

unsigned int sdbmhash(char *s){
    int hash = 0;
    while (*s){
        hash = (hash << 6) + (hash << 16) - hash + *s++;
    }
    return (hash & 0x7fffffffl);
}

int main(){
    char s[1024];
    freopen("str.txt", "r", stdin);
    freopen("elf1.txt", "w", stdout);
    while(true){
        scanf("%s", s);
        if(feof(stdin)) break;
        printf("%d\n", elfhash(s) % 9793);
    }
    return 0;
}


查看结果:
引用
$ sort elf1.txt | less
$ sort elf1.txt | uniq | less
May 16

免费给Felix发短信 不指定

felix021 @ 2009-5-16 16:51 [IT » 网络] 评论(4) , 引用(0) , 阅读(6918) | Via 本站原创
把手头另外一个移动的号码开通了fetion
然后加上昨天发现的那个php的fetion处理了一下
现在大家可以在线免费给我发短信拉!

想自己架设一个?下载这个东西去玩儿吧:
下载文件 (已下载 1877 次)
May 16

linux下批量缩小图片 不指定

felix021 @ 2009-5-16 01:02 [IT » 软件] 评论(0) , 引用(0) , 阅读(5164) | Via 本站原创
(参考网上的资料)用到了 ImageMagick 工具包。
@ Ubuntu
sudo apt-get install imagemagick

引用
$ convert -resize 50%x50% 1.jpg 1_small.jpg
就可以把 1.jpg 的尺寸缩小到越来的1/4
引用
$ convert -sample 400x300 1.jpg 1_small.jpg
就可以把 1.jpg 的尺寸缩小到400x300
注意,两个比率/数字之间的是字母x,不是乘号。

然后来个批量转换的东东(网上的教程是for,虽然我比较喜欢find)
引用
for img in `ls *.jpg`; do convert -resize 50%x50% $img small_$img; done

如果要递归地转换当前目录以及子目录的图像就用find吧:
引用
find -name "*.jpg" -exec convert -resize 50%x50% {} {}.small.jpg
分页: 47/103 第一页 上页 42 43 44 45 46 47 48 49 50 51 下页 最后页 [ 显示模式: 摘要 | 列表 ]