NOIP2008提高组复赛试题及题解 下载本文

全国信息学奥林匹克联赛(NOIP2008)复赛

提高组

一、题目概览

中文题目名称 英文题目名称 可执行文件名 输入文件名 输出文件名 每个测试点时限 测试点数目 每个测试点分值 比较方式 题目类型 笨小猴 word word word,in word.out 1秒 10 10 全文比较 传统 火柴棒等式 matches matches matches.in matches.out 1秒 10 10 全文比较 传统 传纸条 message message message.in message.out 1秒 10 10 全文比较 传统 双栈排序 twostack twostack twostack.in twostack.out 1秒 10 10 全文比较 传统 二、提交源程序文件名

对于Pascal语言 对于C语言 对于C++语言 word.pas word.c word.cpp matches.pas matches.c matches.cpp message.pas message.c message.cpp twostack.pas twostack.c twostack.cpp 三、编译命令(不包含任何优化开关)

对于Pascal语言 对于C语言 对于C++语言 fpc word.pas gcc –o word word.c g++ -o word word.cpp fpc matches.pas gcc –o matches matches.c g++-o matches matches.cpp fpc message.pas gcc –o message message.c g++ -o message message.cpp fpc twostack.pas gcc –o twostack twostack.c g++ -o twostack twostack.cpp 四、运行内存限制

运行内存上限 50M 50M 50M 50M 注意事项:

1. 文件名(程序名和输入输出文件名)必须使用大写。

2. C/C++中函数main()的返回值类型必须是int,程序正常结束时的返回值必须是0。

3. 全国统一评测时采用的机器配置为:CPU 1.9GHz,内存512M,上述时限以此配置为准。各省在自测时可根据具体配置调整时限。

1. 笨小猴

(word.pas/c/cpp)

【问题描述】

笨小猴的词汇量很小,所以每次做英语选择题的时候都很头疼。但是他找到了一种方法,经试验证明,用这种方法去选择选项的时候选对的几率非常大!

这种方法的具体描述如下:假设maxn是单词中出现次数最多的字母的出现次数,minn是单词中出现次数最少的字母的出现次数,如果maxn-minn是一个质数,那么笨小猴就认为这是个Lucky Word,这样的单词很可能就是正确的答案。 【输入】

输入文件word.in只有一行,是一个单词,其中只可能出现小写字母,并且长度小于100。 【输出】

输出文件word.out共两行,第一行是一个字符串,假设输入的的单词是Lucky Word,那么输出“Lucky Word”,否则输出“No Answer”;

第二行是一个整数,如果输入单词是Lucky Word,输出maxn-minn的值,否则输出0。

【输入输出样例1】

word.in error word.out Lucky Word 2 【输入输出样例1解释】

单词error中出现最多的字母r出现了3次,出现次数最少的字母出现了1次,3-1=2,2是质数。

【输入输出样例2】

word.in Olympic word.out No Answer 0 【输入输出样例2解释】

单词olympic中出现最多的字母i出现了2次,出现次数最少的字母出现了1次,2-1=1,1不是质数。

基本的字符串处理,细心一点应该没问题的,不过判断素数时似乎需要考虑下0和1的情况。 var a:array['a'..'z']of integer; s:string;

l,i,max,min,n:integer; ch:char;flag:boolean; begin

assign(input,'word.in'); reset(input);

assign(output,'word.out'); rewrite(output); readln(s);

l:=length(s);

fillchar(a,sizeof(a),0); for i:=1 to l do inc(a[s[i]]); max:=0;min:=100; for ch:='a'to 'z' do

if a[ch]>0 then begin

if a[ch]>max then max:=a[ch]; if a[ch]

for i:=2 to trunc(sqrt(n)) do

if n mod i =0 then begin flag:=false;break;end; if flag then begin writeln('Lucky Word'); writeln(n);end else begin writeln('No Answer');writeln(0);end; close(output);close(input); end.

2. 火柴棒等式

(matches.pas/c/cpp)

【问题描述】

给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A、B、C是用火柴棍拼出的整数(若该数非零,则最高位不能是0)。用火柴棍拼数字0-9的拼法如图所示:

注意:

1. 加号与等号各自需要两根火柴棍

2. 如果A≠B,则A+B=C与B+A=C视为不同的等式(A、B、C>=0) 3. n根火柴棍必须全部用上 【输入】

输入文件matches.in共一行,又一个整数n(n<=24)。 【输出】

输出文件matches.out共一行,表示能拼成的不同等式的数目。

【输入输出样例1】

matches.in matches.out 14 【输入输出样例1解释】 2个等式为0+1=1和1+0=1。

2 【输入输出样例2】

matches.in 18 matches.out 9 【输入输出样例2解释】 9个等式为: 0+4=4 0+11=11 1+10=11 2+2=4 2+7=9 4+0=4 7+2=9 10+1=11 11+0=11

预处理下,然后枚举、剪枝,范围稍微开大点,弄到2000似乎足够了,剪枝后不会超时的。 首先预处理下每个数(0~2000)需要多少个火柴棒,然后枚举A和B,再判断。 参考程序1: program matches; const

inp='matches.in'; oup='matches.out';

num:array['0'..'9'] of integer=(6,2,5,5,4,5,6,3,7,6);//0~9需要的火柴棒数 maxn=1000; var

f:array[0..maxn*2] of longint; i,j,k,n,ans:longint; s:string;

procedure flink; begin

assign(input,inp); reset(input);

assign(output,oup); rewrite(output); end;

procedure fclose; begin

close(input); close(output); end;