2013年慈溪市小学生计算机程序设计竞赛复赛试题解题报告

更新时间:2023-11-12 14:51:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

2013年慈溪市小学生计算机程序设计比赛复赛试题解题报告

1. 统计方格(count.pas)

【问题描述】

给出一张n行m列仅由黑白方格组成的黑白图片(行从上到下1到n编号,列从左到右1到m编号)。如下图是一张由17行18列方格构成的黑白图片,图片中的任意一个方格要么是白色,要么是黑色。

仔细观察这张黑白图片我们可以发现,图中共有60个黑色方格(连续的黑色方格不能算成一个),黑色方格最多的行是第3行和第17行,都为6个,黑色方格最少的行是第5行、第6行、第9行、第12行、第13行、第15行,都为2个。 请编写程序统计黑白图片中黑色方格的总数,黑色方格数目最多的行的行号及黑色方格数目最少的行的行号。 【输入数据】

输入文件count.in:输入从文件中读取,输入共n+1行。 第1行是两个整数n和m(1≤n, m≤100),分别表示黑白图片的行数和列数,两个整 数间用空格分隔。

第2行到第n+1行,描述了图片中每个方格的颜色,黑色用整数0表示,白色用整数1 表示。每行为m个用空格分隔的0或1,其中第i+1行第j 列的整数为Aij(1≤i≤n,1≤j≤m,Aij=0或者Aij=1),表示图片第i 行第j 列位置的方格颜色。 【输出数据】

输出文件count.out:结果输出到文件中。

输出共1行,包含3个整数。分别表示输入文件所表示的黑白图片中黑色方格的总数,黑色方格数目最多的行的行号及黑色方格数目最少的行的行号。注意,如果黑色方格最多的行有多行一样,则输出行号最小的,同样,如果黑色方格最少的行有多行一样,也是输出行号

最小的。

【输入输出样例1】 count.in 6 6

1 1 1 1 1 1 1 0 1 0 0 1 1 0 1 1 0 1 1 0 1 0 1 1 1 0 1 0 0 1 1 1 1 1 1 1 count.out 10 2 1

【样例1解释】

输入的黑白图片的大小为6行6列,第1行0个黑色方格,第2行3个黑色方格,第3行2个黑色方格,第4行2个黑色方格,第5行3个黑色方格,第6行0个黑色方格。所以总共有10个黑色方格,黑色方格最多且行号最小的行是第2行,黑色方格最少且行号最小 的行是第1行。 【输入输出样例2】 count.in 17 18

1 1 1 1 1 1 0 0 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 1 1 1 0 1 1 1 1 0 1 1 1 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 1 1 1 1 1 0 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 count.out 60 3 5

【样例2解释】 样例2如题目描述。 【数据范围约定】

所有的输入数据保证1≤n, m≤100。 【问题分析】

给出一张黑白图片,输出黑色方格的总数,黑色方格数目最多的行的行号及黑色方格数目最少的行的行号。具体见【问题描述】。 【算法分析】

直接模拟,枚举每一行。 【参考程序】

var n,m,max,min,v1,v2,i,j,x,s,tot:longint;

begin

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

assign(output,'count.out'); rewrite(output); max:=-1; min:=101; read(n,m); for i:=1 to n do begin s:=0;

for j:=1 to m do begin read(x); if x=0 then begin

inc(s); inc(tot); end; end;

if s>max then begin

max:=s; v1:=i; end;

if s

min:=s; v2:=i; end; end;

writeln(tot,' ',v1,' ',v2); close(input); close(output); end.

2.转圈游戏(circle.pas)

【问题描述】

n个小朋友(小朋友从0到n-1进行编号)围坐一圈玩游戏。按照顺时针方向依次给 n 个位置编号,也是从0到n-1。最初,第0号小朋友在第0号位置,第1号小朋友在第1号

位置,……,依此类推。

游戏规则如下:每一轮给出两个整数a、b。若a的值等于1,则所有小朋友依次逆时针转b个位置;若a的值等于2,则所有小朋友依次顺时针转b个位置。

比如:a=2,b=3,那么第0号位置上的小朋友顺时针转到第3号位置,第1号位置上的小朋友顺时针转到第4号位置,……,第n-3号位置上的小朋友顺时针转到第0号位置,第n-2号位置上的小朋友顺时针转到第1号位置,第n-1号位置上的小朋友顺时针转到第2号位置,一轮转圈结束。 依照上面的游戏规则,请问进行q轮后,第0到n-1号位置上的小朋友的编号分别是什么? 【输入数据】

输入文件circle.in:输入从文件中读取,输入共q+1行。

第1行是两个整数n和q(1≤n≤100000, 0≤q≤200000),表示n个小朋友要进行q轮转圈游戏,两个整数间用空格分隔。

第2行到第q+1行,每行两个用空格分隔的整数。其中第i+1行两个整数为ai 和bi (ai=1 或者ai=2, 0≤bi≤n-1),表示第i 轮转圈的信息。若ai=1,则所有小朋友依次向逆时针 方向转bi 个位置,若ai=2,则所有小朋友依次向顺时针方向转bi 个位置。 【输出数据】

输出文件circle.out:结果输出到文件中。

输出共n行,每行包含一个整数,第i 行整数表示经过转圈后第i-1号位置上的小朋友的编号。

【输入输出样例1】 circle.in 4 1 2 3

circle.out 1 2 3 0

【样例1解释】

4个小朋友参加转圈游戏,转圈共进行了1轮,在这轮转圈游戏中,所有小朋友依次向顺时针方向转了3个位置,第0号小朋友转到第3号位置,第1号小朋友转到了第0号位置,第2号小朋友转到了第1号位置,第3号小朋友转到了第2号位置,所以最后第0号位置到第3号位置上的小朋友编号分别是1,2,3,0。 【输入输出样例2】 circle.in 5 3 1 1 2 2 1 3

circle.out 2 3 4 0 1

【样例2解释】

5个小朋友参加转圈游戏,转圈共进行了3轮。在第1轮转圈游戏中,所有小朋友依次向逆时针方向转了1个位置。在第2轮转圈游戏中,所有小朋友依次向顺时针方向转了2个位置。在第3轮转圈游戏中,所有小朋友依次向逆时针方向转了3个位置。所以最后第0号位置到第4号位置上的小朋友编号分别是2,3,4,0,1。 【数据范围约定】

对于70%的数据,1≤n≤1000,0≤q≤2000。

对于100%的数据,1≤n≤100000,0≤q≤200000。 【问题分析】

求n个人按输入规则进行q轮转圈后,每个位置上的人对应的编号。 【算法分析】

模拟,只要统计出每个人最后相当于逆时针转了多少距离即可。 【参考程序】

var x,i,v,n,m,a,b:longint;

begin

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

assign(output,'circle.out'); rewrite(output); read(n,m); for i:=1 to m do begin read(a,b);

if a=1 then v:=(v-b) mod n else v:=(v+b) mod n; end;

for i:=0 to n-1 do begin

x:=(i-v) mod n;

while x<0 do x:=x+n;

writeln(x); end;

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

3.排队(queue.pas)

【问题描述】

按身高排队是我们最常用的一种排队方法,一伙小朋友已经非常厌倦了这种排队方式,这次他们打算按每个人的姓名排队,但如果按照姓名的字典序进行排队似乎有点麻烦,所以他们找了一种比较简单的排队方法:根据姓名的长度进行排队,姓名长的排在最前面,姓名短的排在最后面。

姓名的长度他们有这样的约定:每个人的姓名只能由“a”( ASCII码为97)到“z” (ASCII码为122)这26个小写英文字母构成,姓名的长度就是姓名中字母的总个数。 由于小朋友人数比较多,请根据他们的排队方法,编程帮助他们排队吧! 【输入数据】

输入文件queue.in:输入从文件中读取,输入共n+1行。 第1行是一个整数n(1≤n≤15000),表示总共有n个小朋友参加排队(编号为1到n)。 第2行到第n+1行,每行一个字符串,其中第i+1行表示第i 个小朋友的姓名,数据保证每个小朋友都有姓名,并且姓名的长度不超过255。 【输出数据】

输出文件queue.out:结果输出到文件中。

输出共n行,表示经过排队后的小朋友的姓名情况,姓名长的先输出,姓名短的后输出。注意,当小朋友的姓名长度一样时,输出的顺序同输入的顺序(参考样例解释)。 【输入输出样例】 queue.in 3

aoteman guaishou jiqiren queue.out guaishou aoteman jiqiren

【样例解释】

有3个小朋友参加了排队,第1个小朋友的姓名长度为7,第2个小朋友的姓名长度为8,第3个小朋友的姓名长度为7。因为第2个小朋友的姓名最长,所以最先输出,第1个小朋友和第3个小朋友的姓名长度都为7,但在输入中,小朋友“aoteman”在小朋友“jiqiren”的前面,所以先输出“aoteman”,然后输出“jiqiren”。 【数据范围约定】

60%的输入数据保证1≤n≤1000,且每个小朋友的姓名长度不超过100。 80%的输入数据保证1≤n≤8000,且每个小朋友的姓名长度不超过255。 100%的输入数据保证1≤n≤15000,且每个小朋友的姓名长度不超过255。 【问题分析】

给出一些字符串,按要求进行排序。

【算法分析】

排序,可采用双关键字快排。 【参考程序】 var n,i:longint;

a,b:array[1..15000] of longint; s:array[1..15000] of string;

procedure sort(l,r:longint); var i,j,t,mid,m:longint; begin

i:=l; j:=r; mid:=a[(i+j) div 2]; m:=b[(i+j) div 2]; repeat

while (a[i]>mid) or (a[i]=mid) and (b[i]m) do dec(j); if I<=j then begin

t:=a[i]; a[i]:=a[j]; a[j]:=t; t:=b[i]; b[i]:=b[j]; b[j]:=t; inc(i); dec(j); end; until i>j;

if l

begin

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

assign(output,'queue.out'); rewrite(output); readln(n); for i:=1 to n do begin

readln(s[i]);

a[i]:=length(s[i]); b[i]:=i; end; sort(1,n);

for i:=1 to n do writeln(s[b[i]]);

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

4.寻找子矩阵(matrix.pas)

【问题描述】

一个由n行m列构成的矩阵(从上到下对行1到n编号,从左到右对列1到m编号),

第i 行第j 列中有一个正整数Wij。例如下面是一个3行4列的矩阵。

现在从中选取一个p行q列的子矩阵,例如下面黑框中选取的是一个2行3列的子矩阵。

仔细观察会发现,从上面的矩阵中选取2行3列的子矩阵共有4种不同的方法。 现在请你找这样一个子矩阵,满足以下条件:

将子矩阵的q列从左到右编号为1到q,删除子矩阵中所有编号为奇数的列,或者删除子矩阵中所有编号为偶数的列,然后 用子矩阵中剩下的数之和 减掉 子矩阵中被删除的数之和,得到一个结果S,S最大的子矩阵就是我们要找的子矩阵,注意,这样的子矩阵可能有多个。

例如上面黑框中的子矩阵,删除编号为奇数的列(下图1)或删除编号为偶数的列(下图2)。(阴影部分为删除的列)

按照计算规则,图1中剩下的数之和为8,被删除的数之和为9,所以S=-1,图2中剩下的数之和为9,被删除的数之和为8,所以S=1,也就是说当选择这个子矩阵时,S的最大值为1。当然可以选择其他子矩阵来获取更大的S。 【输入数据】

输入文件matrix.in:输入从文件中读取,输入共n+1行。

第一行包含 4 个整数 n、m、p、q (1≤n,m≤1000,1≤p≤n,1≤q≤m),每两个整数之间用一个空格隔开。

接下来n行,每行包含 m 个整数。第i+1行的第j 个整数为Wij(1≤Wij≤100),表示矩 阵中的第i 行第j 列的数,每两个整数之间用一个空格隔开。 【输出数据】

输出文件matrix.out:结果输出到文件中。

输出共一行,包含一个整数,表示最大的S。注意不需要输出你选择的子矩阵。 【输入输出样例】 matrix.in 3 4 2 3 1 5 2 3

2 3 4 2 8 2 4 3 matrix.out 13

【样例解释】

当选择如下子矩阵时,S的值为13,满足最大。

【数据范围约定】

对于30%的数据保证1≤n≤50,1≤m≤50。 对于70%的数据保证1≤n≤300,1≤m≤300。 对于100%的数据保证1≤n≤1000,1≤m≤1000。

另外,所有的数据保证1≤p≤n,1≤q≤m,1≤Wij≤100。 【问题分析】

给出一个二维矩阵,要求从中选取一个p行q列的子矩阵,使 奇数列的和 与 偶数列的和 的差最大。 【算法分析】

对于30%的数据,暴力枚举,时间复杂度为O(n*m*p*q)。

对于70%的数据,用前缀和进行优化,然后进行暴力枚举,时间复杂度为O(n*m*q)。 对于100%的数据,用前缀和进行优化,进行枚举时,不暴力求值,因为只要把左边那列去掉,把右边那列加上即可,时间复杂度为O(n*m)。 【参考程序】 var

n,m,p,q,i,j,s1,s2,ans:longint;

a:array[0..1000,1..1000] of longint; begin

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

assign(output,'matrix.out'); rewrite(output); read(n,m,p,q); for i:=1 to n do for j:=1 to m do begin

read(a[i,j]);

a[i,j]:=a[i,j]+a[i-1,j] end;

for i:=1 to n-p+1 do begin

s1:=0; s2:=0; for j:=1 to q do if odd(j) then

s1:=s1+a[i+p-1,j]-a[i-1,j]

else

s2:=s2+a[i+p-1,j]-a[i-1,j]; if abs(s1-s2) > ans then ans:=abs(s1-s2); for j:=q+1 to m do begin

if odd(j) then

s1:=s1+a[i+p-1,j]-a[i-1,j] else

s2:=s2+a[i+p-1,j]-a[i-1,j]; if odd(j-q) then

s1:=s1-a[i+p-1,j-q]+a[i-1,j-q] else

s2:=s2-a[i+p-1,j-q]+a[i-1,j-q]; if abs(s1-s2) > ans then ans:=abs(s1-s2) end end;

writeln(ans);

close(input); close(output) end.

本文来源:https://www.bwwdw.com/article/cmlv.html

Top