宁波30届小学生程序复赛解题报告.docx
- 文档编号:27842997
- 上传时间:2023-07-05
- 格式:DOCX
- 页数:12
- 大小:19.40KB
宁波30届小学生程序复赛解题报告.docx
《宁波30届小学生程序复赛解题报告.docx》由会员分享,可在线阅读,更多相关《宁波30届小学生程序复赛解题报告.docx(12页珍藏版)》请在冰豆网上搜索。
宁波30届小学生程序复赛解题报告
1.幸运数字
(lucky.cpp/pas/c)
【题目描述】
小李非常喜欢数字4和7,看到一个数字他就想快速计算出因子里面分别有几个4和7,但是智商捉急的他总是要算很久,喜欢编程的你能够帮助他吗?
【输入】
第一行一个整数n,表示给定的数字。
【输出】
两个用空格隔开的数字,分别表示给定数字的因子中4和7的个数。
【样例输入】
112
【样例输出】
21
【样例说明】
112=4*4*7
【数据规模】
50%的数据,3<=n<=230
100%的数据,3<=n<=260
分析:
这里是分解质因数的变形,先考虑数据规模,有多大?
integer是2个字节,也就是16个二进制位,除去符号位,即-1,同理,longint是4个字节,-1,int64是8个字节,-1。
明显必须采用int64。
然后考虑分解质因数的时间复杂度,包含了最多的4,也就30次就能分解了,所以不会超时,至于7的个数,肯定是小于4的,放心用分解质因数。
这题难度可以升级,如果在指定范围内输出每个数字因子里有几个4和7,就要考虑时间复杂度!
代码:
var
x,i:
integer;
a:
array[4..7]ofinteger;
n:
int64;
begin
readln(n);
x:
=4;
repeat
ifnmodx=0then
begin
inc(a[x]);
n:
=ndivx;
end
elseinc(x);
untilx>7;
writeln(a[4],'',a[7]);
end.
2.英雄卡
(card.cpp/pas/c)
【题目描述】
小李非常迷恋收集各种干脆面里面的英雄卡,为此他曾经连续一个月都只吃干脆面这一种零食,但是有些稀有英雄卡真的是太难收集到了。
后来某商场搞了一次英雄卡兑换活动,只要你有三张编号连续的英雄卡,你就可以换任意编号的英雄卡。
小李想知道他最多可以换到几张英雄卡(新换来的英雄卡不可以再次兑换)。
【输入】
第一行,共一个整数n,表示小李拥有的英雄卡数。
第二行,共n个空格隔开的数字ai,表示英雄卡的编号。
【输出】
输出仅有一行,共1个整数,表示小李最多可以换到的英雄卡。
【样例输入】
6
312445
【样例输出】
1
【样例说明】
123三张编号连续,可以换一张,换完后剩下445,不符合兑换规则,无法继续兑换。
【数据规模】
70%数据,1<=n<=1000
100%数据,1<=n<=10000,1<=ai<=100000
分析:
这题明显就是排序+模拟,因为数据最大到10W,且没有负数,直接用计数排序。
然后按顺序模拟兑换即可。
var
i,n,sum,x:
longint;
a:
array[1..100000]ofinteger;
begin
readln(n);
fori:
=1tondo
begin
read(x);
inc(a[x]);
end;
i:
=1;
whilei<=99998do
begin
while(a[i]<>0)and(a[i+1]<>0)and(a[i+2]<>0)do
begin
inc(sum);
dec(a[i]);
dec(a[i+1]);
dec(a[i+2]);
end;
inc(i);
end;
writeln(sum);
end.
3.最强阵容
(battle.cpp/pas/c)
【题目描述】
拿着新换来的英雄卡,小李满心欢喜的准备和同学们PK一下。
他们的游戏规则非常简单,双方把自己的牌绕成一圈,然后指定一个起点,从该张牌开始顺时针方向往后取,谁取出的字符串字典序更小(从左到右开始比较,碰到第一个不一样的字符进行比较,比较规则为a
具体规则可参考样例。
虽然现在小李的牌已经很好了,但是你能不能帮他快速算出起始位置,使得他能够派出最强阵容。
【输入】
第一行n,表示共有n张牌。
第二行共n个用一个空格隔开的小写字母,表示给定的一圈牌起始序列。
【输出】
仅一个整数,能获得最小字典序字符串的起点位置。
如果有多个位置开始的字符串一样,则输出最小的那个位置,且第一个位置从1开始。
【样例输入】
4
bcab
【样例输出】
3
【样例说明】
四个位置取出的字符串分别为bcab,cabb,abbc,bbca,显然最小位置是3。
【数据规模】
30%的数据,1<=n<=10
60%的数据,1<=n<=1000
100%的数据,1<=n<=30000
分析:
这题有陷阱。
先入为主的想法是,重组字符串,然后寻找最小字符串。
1.如果采用移动字符重组字符串,则会超时,因为30000×30000=900000000.O(
)
2.如果用字符串处理函数delete和insert,虽然在重组上不会超时,但会造成另外的问题,内存溢出。
因为这题不得不用ansistring,30000×30000≈107M内存,加上其他的开销,就会爆空间。
上述想法都是按题目意思去理解,所以会陷入误区。
其实可以截取部分字符串就可以了,不需要把所有的字符串重组。
思路是:
因为从第1个位置开始,所以把第一个字符作为新字符串的首字母,然后从下1个位置开始扫描,只要比首字母大就连接起来,但要考虑特殊情形,如果相等也要连接,否则类似aa这样的就变成a和a两个字符串了,所以先要处理连接,不然这种特殊情况就会造成失分。
1.和首字母相比,如果相同则需要连接(跟以前排除空格差不多哦)
2.之后的字母如果比首字母大,则加入连接,再遇到相等则结束。
3.因为是环,所以最后一个字符串取出后,还要跟原字符串的头相比。
这样生成的字符串数组,最多也就30000个字节,空间不会溢出,重组采用分段截取,时间也不会超时,差不多是O(N)。
代码:
type
rd=record
ss:
ansistring;
p:
integer;
end;
var
i,n,j:
integer;
s:
ansistring;
c:
char;
save:
array[1..30000]ofrd;
minstr:
rd;
begin
readln(n);
s:
='';
fori:
=1tondo
begin
read(c);
ifc=''thenread(c);
s:
=s+c;//生成原始字符串
end;
i:
=1;
j:
=0;
whilei<=ndo//扫描原始字符串
begin
inc(j);
save[j].ss:
=save[j].ss+s[i];//新字符串的首个字符
save[j].p:
=i;//记录新字符串的起始位置
while(i begin save[j].ss: =save[j].ss+s[i+1];//首字母后续相同则要连接 inc(i); end; inc(i); while(i<=n)and(save[j].ss[1] begin save[j].ss: =save[j].ss+s[i]; inc(i); end; end; i: =1; while(save[j].ss[1] begin save[j].ss: =save[j].ss+s[i]; inc(i); end; minstr: =save[1]; fori: =2tojdo ifsave[i].ss =save[i]; writeln(minstr.p); end. 4.最强素数 (prime.cpp/pas/c) 【题目描述】 小李在你帮助之下轻松战胜了他的同学们,于是满怀恶意的同学出了一个题目来为难小李,作为小李神一样的队友,你又要出力了。 素数41能写成连续6个素数之和: 41=2+3+5+7+11+13。 现在要求n以内的素数中,能表示为最多连续素数之和的那个数,如果有多个答案,请输出最大的那个素数。 【输入】 仅一行,一个整数n。 【输出】 输出就一个整数,为所求的能表示为最多连续素数和的那个素数。 【样例输入】 100 【样例输出】 41 【样例说明】 41=2+3+5+7+11+13 【数据规模】 30%的数据,1<=n<=1000 60%的数据,1<=n<=10000 80%的数据,1<=n<=100000 100%的数据,1<=n<=1000000 分析: 1.先用筛选法求出素数表,为了方便处理,需把素数保存到数组中 2.寻找n以内的所有素数中,连续素数个数最多的。 所以我们只需要遍历n以内的所有素数,不需要从1遍历到n,这就就是第一点把数组保存到数组中的好处。 3.因为要对n内每个素数进行搜索,所以对当前素数来说,有很多的重复计算,如何减少计算量是这题的难点。 我采用的方法是,假如1~prime[k]个连续素数之和大于x,则减掉第1个素数,并且计数减少1,再判断2~prime[k]是否大于x,如果还大于,则3~prime[k]是否大于x,如果小于了,开始加后面的素数,形成新的和3~prime[k+1],也就是说只改动两端,避免多余的计算。 4.如果在寻找的过程中找到连续的和能等于x,更新当前最优解后,记得要结束寻找,因为后面没有搜索的必要了。 代码: var n,i,j,k,sum,max,count,maxprime: longint; d: array[1..1000000]ofboolean; prime: array[1..80000]oflongint; flag: boolean; begin readln(n); i: =2; d[1]: =true; whilei<=trunc(sqrt(n))do begin ifd[i]then begin inc(i); continue; end; j: =i+i; whilej<=ndo begin d[j]: =true; j: =j+i; end; inc(i); end; fori: =2tondo ifnotd[i]then begin inc(k); prime[k]: =i; end; i: =1; while(prime[i]<=n)and(prime[i]<>0)do begin flag: =false; sum: =0; count: =0; k: =1; forj: =1to10do begin whilek<=ido begin ifsum>prime[i]then begin sum: =sum-prime[j]; dec(count); break; end elseifsum=prime[i]then begin ifcount>=maxthen begin max: =count; maxprime: =prime[i]; end; flag: =true; break; end elsebegin sum: =sum+prime[k]; inc(count); inc(k); end; end; ifflagthenbreak; end; inc(i); end; ifn=3thenwriteln(n) elsewriteln(maxprime); end.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 宁波 30 小学生 程序 复赛 解题 报告