NOIP普及组复赛试题附题解.docx

上传人:b****6 文档编号:8543263 上传时间:2023-01-31 格式:DOCX 页数:13 大小:21.19KB
下载 相关 举报
NOIP普及组复赛试题附题解.docx_第1页
第1页 / 共13页
NOIP普及组复赛试题附题解.docx_第2页
第2页 / 共13页
NOIP普及组复赛试题附题解.docx_第3页
第3页 / 共13页
NOIP普及组复赛试题附题解.docx_第4页
第4页 / 共13页
NOIP普及组复赛试题附题解.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

NOIP普及组复赛试题附题解.docx

《NOIP普及组复赛试题附题解.docx》由会员分享,可在线阅读,更多相关《NOIP普及组复赛试题附题解.docx(13页珍藏版)》请在冰豆网上搜索。

NOIP普及组复赛试题附题解.docx

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.

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1