NOIP普及组复赛试题附题解.docx
- 文档编号:8543263
- 上传时间:2023-01-31
- 格式:DOCX
- 页数:13
- 大小:21.19KB
NOIP普及组复赛试题附题解.docx
《NOIP普及组复赛试题附题解.docx》由会员分享,可在线阅读,更多相关《NOIP普及组复赛试题附题解.docx(13页珍藏版)》请在冰豆网上搜索。
NOIP普及组复赛试题附题解
noip2005普及组解题报告
陶陶摘苹果
【文件名】:
apple.pas/c/cpp
【问题描述】
陶陶家的院子里有一棵苹果树,每到秋天树上就会结出10个苹果。
苹果成熟的时候,陶陶就会跑去摘苹果。
陶陶有个30厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。
现在已知10个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度,请帮陶陶算一下她能够摘到的苹果的数目。
假设她碰到苹果,苹果就会掉下来。
【输入文件】
输入文件apple.in包括两行数据。
第一行包含10个100到200之间(包括100和200)的整数(以厘米为单位)分别表示10个苹果到地面的高度,两个相邻的整数之间用一个空格隔开。
第二行只包括一个100到120之间(包含100和120)的整数(以厘米为单位),表示陶陶把手伸直的时候能够达到的最大高度。
【输出文件】
输出文件apple.out包括一行,这一行只包含一个整数,表示陶陶能够摘到的苹果的数目。
【样例输入】
100 200 150 140 129 134 167 198 200 111
110
【样例输出】
5
分析:
拿到这道题,我觉得还是比较简单的。
由于数据范围都不超过200,用integer完全就足够了,具体步骤如下:
1. 读入
2. 循环 1 to 10
3. 判断,找出最优解
4. 输出
【程序清单】
program apple;
var
i,n,s:
integer;
a:
array[1..10] of integer;
begin
assign(input,'apple.in');
reset(input);
for i:
=1 to 10 do read(a[i]);
read(n);
s:
=0;
for i:
=1 to 10 do
if n+30>=a[i] then s:
=s+1;
close(input);
assign(output,'apple.out');
rewrite(output);
write(s);
close(output);
end.
校门外的树
【文件名】tree.pas/c/cpp
【问题描述】
某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。
我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。
由于马路上有一些区域要用来建地铁。
这些区域用它们在数轴上的起始点和终止点表示。
已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。
现在要把这些区域中的树(包括区域端点处的两棵树)移走。
你的任务是计算将这些树都移走后,马路上还有多少棵树。
【输入文件】
输入文件tree.in的第一行有两个整数L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。
接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。
【输出文件】
输出文件tree.out包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。
【样例输入】
500 3
150 300
100 200
470 471
【样例输出】
298
【数据规模】
对于20%的数据,区域之间没有重合的部分;
对于其它的数据,区域之间有重合的情况。
分析:
由于这道题存在着区域之间重合的情况,所以最好用一个数组表示状态,现将其全部置为1,若在区域之间就将其置为0。
再在最后进行判断,计算值为1的个数。
【程序清单】
program tree;
var
b:
array[0..10000] of integer;
a:
array[1..500,1..2] of integer;
j,s,l,i,m:
integer;
begin
assign(input,'tree.in');
reset(input);
assign(output,'tree.out');
rewrite(output);
read(l,m);
for i:
=1 to m do
begin
read(a[i,1]);
read(a[i,2]);
end;
for i:
=0 to l do b[i]:
=1;
for i:
=1 to m do
for j:
=a[i,1] to a[i,2] do b[j]:
=0;
s:
=0;
for i:
=0 to l do
if b[i]=1 then s:
=s+1;
writeln(s);
close(input);
close(output);
end.
采药
【文件名】:
medic.pas/c/cpp
【问题描述】
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。
为此,他想拜附近最有威望的医师为师。
医师为了判断他的资质,给他出了一个难题。
医师把他带到一个到处都是草药的山洞里对他说:
“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。
我会给你一段时间,在这段时间里,你可以采到一些草药。
如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。
”
如果你是辰辰,你能完成这个任务吗?
【输入文件】
输入文件medic.in的第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。
接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
【输出文件】
输出文件medic.out包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
【样例输入】
70 3
71 100
69 1
1 2
【样例输出】
3
【数据规模】
对于30%的数据,M <= 10;
对于全部的数据,M <= 100。
分析:
由于其中的数据比较大,用普通简单的搜索肯定无法在限定时间内完成,所以本题采用了动态规划来完成。
这样就容易多了。
【程序清单】
方法一:
type
data=record
time,price:
longint;
end;
var
t,m,ans:
longint;
med:
array[1..100]ofdata;
countline:
array[0..1000]oflongint;
procedureindata;
var
i:
integer;
begin
assign(input,'medic.in');
reset(input);
readln(t,m);
fori:
=1tomdo
readln(med[i].time,med[i].price);
close(input);
end;
procedureoutdata;
begin
assign(output,'medic.out');
rewrite(output);
writeln(ans);
close(output);
end;
procedurecount;
var
i,j,k:
longint;
begin
fillchar(countline,sizeof(countline),0);
fori:
=1tomdo
forj:
=tdownto1do
begin
if(j>=med[i].time)and(med[i].price+countline[j-med[i].time]>countline[j])then
countline[j]:
=med[i].price+countline[j-med[i].time];
end;
ans:
=countline[t];
end;
begin
indata;
count;
outdata;
end.
解法二:
program medic;
var
max,t,m,i,j:
Integer;
a,b:
array[0..1000,0..1000] of integer;
begin
assign(input,'medic.in');
reset(input);
assign(output,'medic.out');
rewrite(output);
read(t,m);
for i:
=1 to m do
begin
read(b[i,1]);
read(b[i,2]);
end;
for i:
=1 to m do
begin
for j:
=1 to b[i,1]-1 do a[i,j]:
=a[i-1,j];
for j:
=b[i,1] to t do
begin
if (b[i,1]=j) and (b[i,2]>a[i-1,j]) then a[i,j]:
=b[i,2];
if b[i,2]+a[i-1,j-b[i,1]]>a[i-1,j] then
a[i,j]:
=b[i,2]+a[i-1,j-b[i,1]]
else a[i,j]:
=a[i-1,j];
end;
end;
writeln(a[m,t]);
close(input);
close(output);
end.
circle.pas/c/cpp
【问题描述】
乐乐是一个聪明而又勤奋好学的孩子。
他总喜欢探求事物的规律。
一天,他突然对数的正整数次幂产生了兴趣。
众所周知,2的正整数次幂最后一位数总是不断的在重复2,4,8,6,2,4,8,6……我们说2的正整数次幂最后一位的循环长度是4(实际上4的倍数都可以说是循环长度,但我们只考虑最小的循环长度)。
类似的,其余的数字的正整数次幂最后一位数也有类似的循环现象:
循环
循环长度
2
2、4、8、6
4
3
3、9、7、1
4
4
4、6
2
5
5
1
6
6
1
7
7、9、3、1
4
8
8、4、2、6
4
9
9、1
2
这时乐乐的问题就出来了:
是不是只有最后一位才有这样的循环呢?
对于一个整数n的正整数次幂来说,它的后k位是否会发生循环?
如果循环的话,循环长度是多少呢?
注意:
1. 如果n的某个正整数次幂的位数不足k,那么不足的高位看做是0。
2. 如果循环长度是L,那么说明对于任意的正整数a,n的a次幂和a+L次幂的最后k位都相同。
【输入文件】
输入文件circle.in只有一行,包含两个整数n(1<=n<10100)和k(1<=k<=100),n和k之间用一个空格隔开,表示要求n的正整数次幂的最后k位的循环长度。
【输出文件】
输出文件circle.out包括一行,这一行只包含一个整数,表示循环长度。
如果循环不存在,输出-1。
【样例输入】
322
【样例输出】
4
【数据规模】
对于30%的数据,k<=4;
对于全部的数据,k<=100。
刚刚看到这个题目,就知道要进行高精度的运算,这个地球人都知道。
如果用直接模拟的算法,我们来计算一下时间复杂度。
1、每计算一次高精度乘法需要O(k2)//这个算法在网上有相关的优化,本人水平太差,没能掌握
2、总共需要进行至少L次高精度乘法,而L的最大值为10^100。
期望得分:
30。
由此,我们不得不对这个算法进行改进。
请看下面的推理。
因为如果循环长度是L,那么说明对于任意的正整数a,n的a次幂和a+L次幂的最后k位都相同。
所以如果循环长度是L,那么说明对于任意的正整数a,n的a次幂和a+L次幂的最后k-1位都相同。
为了方便,我们把循环长度为K的时候对应的L记为F(K)。
那么可以找出一个关系
F(K)=m*F(K-1),
其中m是整数。
由抽屉原则,我们可以容易地想到,m<=10。
由此,我们可以从F(K-1)轻易模拟求出F(K)。
需要说明的是,在求m的时候判断时要先乘上一个n。
这样我们的算法就诞生了。
它的时间复杂度是
。
实践证明,这个算法比传说中的标程要快好多。
在我小小的C31.0G上面竟然只需要1.73s。
给出源代码:
(写程序的时候没看原来的题目,变量名起得比较乱。
)
programcircle;
varstart,//一开始的n
time,//每一次要向当前的运算结果上去乘的那个数。
want,//其实want=start,具体的不同请看程序,want的作用是和now进行比对,检查是否找到了合适的m
now,//现在已经运算到的数
ans:
string;//答案
add,//m
n:
integer;//k
i:
integer;
procedureinit;
vars2,s:
string;t:
integer;
begin
assign(input,'circle.in');reset(input);
readln(s);
close(input);
t:
=pos('',s);
now:
=copy(s,1,t-1);
time:
=now;
want:
=now;
whilelength(want)<101dowant:
='0'+want;//为了避免越界,在want前面加0(如果n的某个正整数次幂的位数不足k,那么不足的高位看做是0。
)
s2:
=copy(s,t+1,255);
val(s2,n,t);
start:
=copy(now,length(now)-n+1,255);
end;
functionmin(a,b:
integer):
integer;
begin
ifa<=bthenmin:
=aelsemin:
=b;
end;
functionmultiply(a,b:
string):
string;//一个高精度乘高精度的function
vara1,a2,a3:
array[1..128]ofinteger;
k,t,l1,l2:
integer;
begin
l1:
=length(a);l2:
=length(b);
fort:
=1tol1doa1[t]:
=ord(a[l1-t+1])-48;
fort:
=1tol2doa2[t]:
=ord(b[l2-t+1])-48;
fillchar(a3,sizeof(a3),0);
fort:
=1tol1do
fork:
=1tomin(103-t,l2)do
inc(a3[t+k-1],a1[t]*a2[k]);
t:
=1;
whilet<102dobegin
ifa3[t]>=10thenbegin
inc(a3[t+1],a3[t]div10);
a3[t]:
=a3[t]mod10;
end;
inc(t);
end;
a:
='';
k:
=100;
whilea3[k]=0dobegin
dec(k);
ifk=0thenbreak;
end;//如果高精度的乘法结果只有0的话就直接输出0
ifk=0thena:
='0';
whilek>0dobegin
a:
=a+chr(48+a3[k]);
dec(k);
end;
multiply:
=a;
end;
functioncheck(k:
integer):
boolean;//检查最后k位是否已经得到了循环长度L
varnow2:
string;
begin
now2:
=multiply(now,start);
check:
=(now2[length(now2)-k+1]=want[length(want)-k+1])
end;
functionmulinteger(a:
string;b:
integer):
string;//高乘单
vara1,a3:
array[1..128]ofinteger;
t,k,l1:
integer;
begin
l1:
=length(a);
fort:
=1tol1doa1[t]:
=ord(a[l1-t+1])-48;
fillchar(a3,sizeof(a3),0);
fort:
=1tol1do
a3[t]:
=a1[t]*b;
t:
=1;
whilet<102dobegin
ifa3[t]>=10thenbegin
inc(a3[t+1],a3[t]div10);
a3[t]:
=a3[t]mod10;
end;
inc(t);
end;
a:
='';
k:
=100;whilea3[k]=0dodec(k);
whilek>0dobegin
a:
=a+chr(48+a3[k]);
dec(k);
end;
mulinteger:
=a;
end;
procedurenoanswer;//无解
begin
assign(output,'circle.out');rewrite(output);
writeln(-1);
close(output);
halt;
end;
begin
init;
ans:
='1';//F(0)=1
i:
=0;
while((check(i+1))and(i 。 。 ifi repeat inc(i); add: =1; repeat inc(add); now: =multiply(now,time); ifadd>10thennoanswer; until(check(i))and(add>1); ans: =mulinteger(ans,add); while((check(i+1))and(i time: =now; untili>=n; assign(output,'circle.out');rewrite(output); writeln(ans); close(output); end.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- NOIP 普及 复赛 试题 题解