Climber.pI的OI之路

Through the darkest dark,may we see the light.

#

初赛零散复习

完善程序最好总结一下以前题目常常要你填出来的语句类型。这个每年都差不多的,想不出来是可以回忆一下有哪些可能填的语句,再放到程序里面看是否合适。

龙芯 http://baike.baidu.com/view/3625.htm
IBM Power系列http://www.enet.com.cn/article/2010/0228/A20100228615002.shtml
AMD http://china.amd.com.cn/processors/ComputingSolutions/default.aspx
Intel 酷睿i系列 http://baike.baidu.com/view/3282306.htm
计算机辅助系统 http://baike.baidu.com/view/1298192.html
ASCII码 http://zhidao.baidu.com/question/94328098.html?fr=ala0
图灵 http://baike.baidu.com/view/2130.htm

哈夫曼树 http://baike.baidu.com/view/127820.htm
多叉转二叉 http://hi.baidu.com/%C6%AE%BB%A8%C4%EA%B4%FA/blog/item/5ec37212ce87fbddf7039e84.html

posted @ 2010-10-13 21:53 Climber.pI 阅读(174) | 评论 (0)编辑 收藏

NOIp 2004 合并果子

NOIp中很少见的数据结构的题目,可以用堆实现,也可以用两条队列. 用堆实现,调了很久 = =
需要注意down函数的边界问题.

 1#include<stdio.h>
 2#include<string.h>
 3#include<iostream>
 4using namespace std;
 5int n, h[10010];
 6struct heap{
 7    void swap(int*i, int*j){
 8        int k = *i; *= *j; *= k;
 9    }

10    void up(int k){
11        while (k > 1)
12            if (h[k/2> h[k]) {
13                swap(&h[k/2], &h[k]);
14                k /= 2;
15            }
else break;
16    }

17    void down(int k){
18        while (2*<= n){
19            int l = 2*k, r = l<? l+1 : l;
20            if (h[r] < h[l]) l++;
21            if (h[k] > h[l]){
22                swap(&h[k], &h[l]);
23                k = l;
24            }
else break;
25        }

26    }

27    void insert(int x){
28        h[++n] = x;
29        up(n);
30    }

31    void del(int k){
32        swap(&h[k], &h[n--]);
33        
34        down(k);
35    }

36    int pop(){
37        del(1);
38        return h[n+1];
39    }

40}
;
41heap hp; 
42int main(){
43    int i, sum = 0;
44    scanf("%d"&n);
45    for (i = 1; i <= n; i++)
46    scanf("%d"&h[i]);
47    for (i = n/2; i > 0; i--) hp.down(i);
48    while (n > 1){
49        int x = hp.pop(), y = hp.pop();
50        sum += x+y;
51        hp.insert(x+y);
52    }

53    printf("%d\n", sum);
54}

55

posted @ 2010-10-12 21:43 Climber.pI 阅读(397) | 评论 (0)编辑 收藏

NOIp 2008 初赛

78 = 12+15+5+32+14,上80还是很困难.

1.二分查找
       设内部结点的总数为n=2^h-1,则判定树是深度为h=log(n+1)的满二叉树(深度h不计外部结点)。树中第k层上的结点个数为2k-1,查找它们所需的比较次数是k。因此在等概率假设下,二分查找成功时的平均查找长度为:ASLbn ≈ log(n+1)-1
       二分查找在查找失败时所需比较的关键字个数不超过判定树的深度,在最坏情况下查找成功的比较次数也不超过判定树的深度。

2.问题求解第二题
21本书中选4本,任意两本编号不相邻.
去掉3个间隔,C(18,4)=3060.

排列组合题总是简单的出乎意料. = =

3.快速排序算法不熟



今天突然发现很多O(nlogn)级别的算法都和树有很深的关系,遍历的过程通常都是生成某种树,然后查找长度和比较次数通常和树的深度相关.

posted @ 2010-10-11 21:15 Climber.pI 阅读(213) | 评论 (0)编辑 收藏

排序算法总结

1.直接插入排序 O(n^2) 稳定
2.希尔排序 O(n^1.3) 不稳定
3.直接选择排序 O(n^2) 不稳定
4.堆排序 O(nlogn) 不稳定
5.冒泡排序 O(n^2) 稳定
6.快速排序 O(nlogn) 不稳定 =>可以看做构造二叉排序树
7.归并排序 O(nlogn) 稳定

整理自《奥赛经典·信息学》 第5章,原理略.

posted @ 2010-10-11 20:56 Climber.pI 阅读(177) | 评论 (0)编辑 收藏

[整理]表达式树

[原文]http://blog.csdn.net/guocai_yao/archive/2009/04/11/4065718.aspx

1.树的遍历法
通过中缀表达式,构造表达式树,然后利用前序或者后序遍历.

2.括号转移法
这里我给出一个中缀表达式

a+b*c-(d+e)

第一步:按照运算符的优先级对所有的运算单位加括号

           式子变成拉:((a+(b*c))-(d+e))
第二步:转换前缀与后缀表达式
        前缀:把运算符号移动到对应的括号前面
                则变成拉:-( +(a *(bc)) +(de))
                把括号去掉:-+a*bc+de  前缀式子出现
        后缀:把运算符号移动到对应的括号后面
                则变成拉:((a(bc)* )- (de)+ )-
                把括号去掉:abc*-de+-  后缀式子出现
发现没有,前缀式,后缀式是不需要用括号来进行优先级的确定的。

posted @ 2010-10-11 20:50 Climber.pI 阅读(307) | 评论 (0)编辑 收藏

NOIp 2005 过河

线性dp,但是范围很变态. = =

30%的方程很容易想到:
[状态] f[i]表示从0到i点最少踩到的石子数, stone[i]表示i点有无石子;
[方程] f[i] = max{f[i-j] + stone[i]} (S<=j<=T)
[初始化] f[0] = 0, 其他赋值为无限大.

在实现的时候需要把方程变化为 f[i+j] = max{f[i] + stone[i+j]},不然在[1,S]会出现很诡异的结果.
 
由于m远远小于l,整个序列上的石子非常稀疏.所以可以减少状态.但是目前对此还是有些不解.
某种思路是,将石子间距大[1,2,..,9,10]=2520的逐次减至小于2520.注意要在收尾增加0和l两个"石子",这样计算新的l较为方便.


 1#include<stdio.h>
 2#include<iostream>
 3using namespace std;
 4#define MAXN 1000000;
 5bool L[200000= {0};
 6int f[200000= {0}, stone[110= {0};
 7int min(int x, int y){return x < y ? x : y;}
 8void swap(int x, int y){
 9    int k = stone[x];
10    stone[x] = stone[y];
11    stone[y] = k;
12}

13int main(){
14    int l, S, T, M, i, j;
15    scanf("%d%d%d%d"&l, &S, &T, &M);
16    for (i = 1; i <= M; i++) scanf("%d"&stone[i]);
17    stone[0= 0;
18    for (i = 1; i < M; i++)
19        for (j = i+1; j <= M; j++)
20            if (stone[i] > stone[j]) swap(i, j);
21    stone[++M] = l;
22    for (i = 1; i <= M; i++){
23        while (stone[i] - stone[i-1> 2520) stone[i] -= 2520;
24        if (i != M) L[stone[i]] = 1;
25    }

26    l = stone[M--];
27    for (i = 0; i <= l; i++) f[i] = MAXN; f[0= 0;
28    for (i = 0; i < l; i++)
29        for (j = S; j <= T; j++){
30            int k = i+j;
31            if (i + j >= l) k = l;
32            f[k] = min(f[k], f[i]+L[i]);
33        }

34    printf("%d\n", f[l]);
35}

posted @ 2010-10-08 21:54 Climber.pI 阅读(797) | 评论 (2)编辑 收藏

NOIp 2003 加分二叉树

形DP,需要记录方案,并注意空树的情况.
[状态]f[i][j]从结点i到j的最大加分值
[方程]f[i][j] = max{f[i][k-1]*f[k+1][j]+a[k]} (i<=k<=j)

实现方程的时候循环顺序非常关键:结点数由小到大循环.否则会出现需要的值未计算的情况.
记录方案可以用一个数组d[i][j]记录k,然后递归寻找方案并记录.

 1 #include<stdio.h>
 2 #include<iostream>
 3 using namespace std;
 4 int f[35][35] = {0}, d[35][35] = {0}, ans[35] = {0}, t = 0;
 5 void print(int start, int end){
 6     if (start > end) return;
 7     if (start == end) {ans[++t] = start; return;}
 8     ans[++t] = d[start][end];
 9     print(start, d[start][end]-1);
10     print(d[start][end]+1, end);
11 }
12 int main(){
13     int n, a[35] = {0}, i, j, k, l;
14     scanf("%d", &n);
15     for (i = 1; i <= n; i++){
16         scanf("%d", &a[i]);
17         f[i][i-1] = 1;
18         f[i][i] = a[i];
19     }
20     for (l = 2; l <= n; l++)
21         for (i = 1; i <= n; i++)
22             for (k = i; k <= i+l-1; k++){
23                 j = i+l-1;
24                 if (f[i][j] < f[i][k-1]*f[k+1][j] + a[k]){
25                     f[i][j] = f[i][k-1]*f[k+1][j] + a[k];
26                     d[i][j] = k;
27                 }
28             }
29     printf("%d\n", f[1][n]);
30     print(1, n);
31     for (i = 1; i < t; i++) printf("%d ", ans[i]);
32     printf("%d\n", ans[t]);
33 }
34 


posted @ 2010-10-05 11:10 Climber.pI 阅读(1003) | 评论 (4)编辑 收藏

NOIp 2006 金明的预算方案

题目中附件不超过2个,因而主附件存在4种不同的存取情况,可以转化为分组背包问题.
[状态]f[k][v]表示添加前k组物品,剩余空间为v时的最大值
[方程]f[k][v] = max{f[k-1][v], f[k-1][v-c[i]]+w[i]}

注意循环顺序.(参见《背包九讲》)

需要注意的问题(2次WA):
1.仔细读题,确定编号对应的物品.
2.注意到方程中的参数非负(背包类问题需注意).

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<iostream>
 4 using namespace std;
 5 int c[65][4], w[65][4], f[32000], set[70] = {0};
 6 int max(int a, int b){return a > b ? a : b;}
 7 int main(){
 8     int n, m, v, p, q, i, j, t = 0;
 9     FILE *fout = fopen("budget.out", "w");
10     memset(c, -1, sizeof(c));
11     memset(w, -1, sizeof(w));
12     memset(f, 0, sizeof(f));
13     scanf("%d%d", &n, &m);
14     for (i = 0; i < m; i++){
15         scanf("%d%d%d", &v, &p, &q);
16         j = 0;
17         if (!q) {
18             c[++t][0] = v;
19             w[t][0] = v*p;
20             set[i+1] = t;
21         }
22         else{
23             q = set[q];
24             if (w[q][1] == -1){
25                 //printf("dgfdgds\n");
26                 c[q][1] = c[q][0] + v;
27                 w[q][1] = w[q][0] + v*p; 
28             }
29             else if (w[q][2] == -1){
30                 c[q][2] = c[q][0] + v;
31                 w[q][2] = w[q][0] + v*p; 
32                 c[q][3] = c[q][1] + v;
33                 w[q][3] = w[q][1] + v*p; 
34             }
35         }
36     }
37     for (i = 1; i <= t; i++)
38         for (v = n; v >= 0; v--)
39             for (j = 0; j < 4; j++)
40                 if (c[i][j] != -1 && v-c[i][j] >= 0){
41                     f[v] = max(f[v], f[v-c[i][j]]+w[i][j]);
42                 }
43     printf("%d\n", f[n]);
44 }
45 


posted @ 2010-10-05 10:11 Climber.pI 阅读(432) | 评论 (0)编辑 收藏

NOIp 2009 初赛

时间几乎用满了,多选题很偏,73.5,全市第五.

[得分情况]

选择题
问题解决
阅读程序写结果
完善程序
总分
得分
12+7.5
0
8+8+8+8
10+12
73.5
[结论]
1.数学太弱了.

2.回去背选择题
3.全市前十五无压力,争取前五.
4.抓紧搞复赛
5.刷作业 = =

[真知灼见]
关于阅读程序的题目
1.弄清变量在程序中的作用.
2.利用变量表示变量,而不要直接计算数值.

看了各种题解后发现错的好猥 - -
下周果断刷五三排列组合、二项式定理

posted @ 2010-10-04 19:34 Climber.pI 阅读(164) | 评论 (0)编辑 收藏

转:在博客园日志中显示数学公式(旧,ASCIIMathML.js版说明)

http://www.cppblog.com/Climber-pI/archive/2010/10/04/128557.html

【貌似CPU占用率会突然很高】

昨天写短消息给博客园开发团队,询问如果能在博客园的日志里更好的编辑或是使用数学公式。之前也在网上查过,貌似对ASCIIMathML有不错的评价,希望能在博客园的日志里也能用得上。

今天下班回来就看到回复的消息,内容如下:

ASCIIMathML.js的确不错。 
            由于这个脚本比较大,默认就不加载了。 
           你可以在页首html中加上这个脚本的引用: 
           <script type="text/javascript" src="http://common.cnblogs.com/script/ASCIIMathML.js"></script>

感动啊,这么快就给出了回复,体贴!谢谢啦!

真是开心啊,为了这个“小”功能我已经愁了很久了,好了,能有很好的代码高亮和数学公式显示~我已经满足了,呵呵。

PS:

试了试,访问的速度是会慢下一点来,忍了~!嘿嘿。下面顺便简单介绍下ASCIIMathML.js和支持的浏览器。

ASCIIMathML.js是一种将ASCII符号翻译成直观的MathML(HTML版本)的开源JavaScript脚本。

您只要遵循简单的语法,用普通的ASCII字母和符号,就可以在网页上输入并显示出漂亮的数学公式。这些公式遵循W3C标准,目前在Netscape7.1/Mozilla/Firefox下可以直接观看,如果您用的是Internet Explorer和以之为内核的其它浏览器(如Maxthon或者GreenBrowser等),只需要下载一个插件。(下载插件MathPlayer,下载字体文件)

posted @ 2010-10-04 11:53 Climber.pI 阅读(691) | 评论 (0)编辑 收藏

仅列出标题
共8页: 1 2 3 4 5 6 7 8