NOIP提高组复赛模拟试题.docx
- 文档编号:29987168
- 上传时间:2023-08-04
- 格式:DOCX
- 页数:19
- 大小:53.38KB
NOIP提高组复赛模拟试题.docx
《NOIP提高组复赛模拟试题.docx》由会员分享,可在线阅读,更多相关《NOIP提高组复赛模拟试题.docx(19页珍藏版)》请在冰豆网上搜索。
NOIP提高组复赛模拟试题
全国青少年信息学奥林匹克
联赛复赛模拟试题
湖南省长沙市第一中学周祖松
试题名称
infinit
remove
game
fire
目录
infinit
remove
game
fire
输入文件名
infinit.in
remove.in
game.in
fire.in
输出文件名
infinit.out
remove.out
game.out
fire.out
试题类型
非交互式程序题
非交互式程序题
非交互式程序题
非交互式程序题
附加文件
无
无
无
无
时限
0.1秒
0.1秒
0.1秒
0.1秒
1.无限序列
(infinit.pas/c/cpp)
【问题描述】
我们按以下方式产生序列:
1、开始时序列是:
"1";
2、每一次变化把序列中的"1"变成"10","0"变成"1"。
经过无限次变化,我们得到序列"1011010110110101101..."。
总共有Q个询问,每次询问为:
在区间A和B之间有多少个1。
任务写一个程序回答Q个询问
输入第一行为一个整数Q,后面有Q行,每行两个数用空格隔开的整数a,b。
输出共Q行,每行一个回答
约定
∙1<=Q<=5000
∙1<=a<=b<263
样例
infinit.in
infinit.out
1
28
4
分析:
我们先看看序列变化规律,S1="1",S2="10",S3="101",S4="10110",S5="10110101",等等.Si是S(i+1)的前缀。
序列Si是由序列S(i-1)和S(i-2),连接而成的。
即Si=Si-1+Si-2(实际上上是Fibonacci数列)。
找到规律以后,我们可以可以用递归的方法求出从从位置1到位置X之间所有的1的个数,用一个函数F计算,结果为f(b)-f(a-1)。
时间复杂度为:
O(Q*logMAX_VAL)
此题需要先找出数学规律,再进用递归实现。
主要考查选手的数学思维能力和递归程序的实现。
源程序:
const
nn=92;//进行92次的数列扩展后,数列长度就会超过给定的数据范围,
var
f,ft:
array[0..nn]ofint64;
q,i,j,l1,l2:
longint;
a,b:
qword;
procedureprapre;{预处理}
vari:
longint;
begin
f[0]:
=1;f[1]:
=1;
ft[0]:
=0;ft[1]:
=1;
fori:
=2tonndo
begin
f[i]:
=f[i-1]+f[i-2];
ft[i]:
=ft[i-1]+ft[i-2];
end;
end;
functionfind(a:
int64;ll:
longint):
int64;{求这个数列的前a个有多少个1}
begin
ifa=0thenexit(0);
find:
=0;
ifa=f[ll]thenfind:
=ft[ll]else
ifa<=f[ll-1]thenfind:
=find(a,ll-1)
elsefind:
=ft[ll-1]+find(a-f[ll-1],ll-2);
end;
begin
assign(input,'infinit.in');reset(input);
assign(output,'infinit.out');rewrite(output);
prapre;
readln(q);
fori:
=1toqdo
begin
readln(a,b);
writeln(find(b,nn)-find(a-1,nn));
end;
close(input);close(output);
end.
2.删数
(remove.pas/c/cpp)
【问题描述】
有N个不同的正整数数x1,x2,...xN排成一排,我们可以从左边或右边去掉连续的i个数(只能从两边删除数),1<=i<=n,剩下N-i个数,再把剩下的数按以上操作处理,直到所有的数都被删除为止。
每次操作都有一个操作价值,比如现在要删除从i位置到k位置上的所有的数。
操作价值为|xi–xk|*(k-i+1),如果只去掉一个数,操作价值为这个数的值。
任务
如何操作可以得到最大值,求操作的最大价值。
InputData
输入文件remove.in的第一行为一个正整数N,第二行有N个用空格隔开的N个不同的正整数。
OutputData
输出文件remove.out包含一个正整数,为操作的最大值
约束和提示
3<=N<=100
N个操作数为1..1000之间的整数。
样例
remove.in
6
542919621133118
remove.out
768
说明,经过3次操作可以得到最大值,第一次去掉前面3个数54、29、196,操作价值为426。
第二次操作是在剩下的三个数(21133118)中去掉最后一个数118,操作价值为118。
第三次操作去掉剩下的2个数21和133,操作价值为224。
操作总价值为426+118+224=768。
分析:
这是一个基本的动态规划问题
我们用F[i][j]表示按规则消去数列a[i..j]得到的的最大值;
删除第i个数得到的最大值为a[i];
删除a[i..j]得到的最大值为:
一次性删除数列a[i..j]得到的值是|a[i]-a[j]|*(j-i+1)或者是先删除a[i..k]再删除a[k+1..j],k在i到j-1之间,得到的值是F[i][k]+F[k+1][j].
我们得到状态转移方程:
F[i][i]=a[i],fori=1..N
对于任意的i F[i][j]=max{|a[i]-a[j]|*(j-i+1),f[i][i]+f[i+1][j],F[i][i+1]+F[i+2][j],...,F[i][j-1]+F[j][j]} F[1,n]为所求的解 时间复杂度: o(N^3); 此题需要选手对算法的时间复杂度进行分析,简单的搜索是不能在规定时间内求出结果,必需使用高效的算法,主要考查选手运用高效算法——动态规划解决问题的能力。 源程序: var n: longint; a: array[1..100]oflongint; f: array[0..101,0..101]oflongint; procedureinit; vari: longint; begin readln(n); fori: =1tondoread(a[i]); end; functionwork(i,k: longint): longint; begin ifi=kthenexit(a[i]); exit(abs(a[i]-a[k])*(k-i+1)); end; functionmax(a,b: longint): longint; begin ifa>bthenmax: =aelsemax: =b; end; proceduremain; vari,j,p: longint; begin fillchar(f,sizeof(f),0); fori: =1tondof[i,i]: =a[i]; fori: =ndownto1do forj: =i+1tondo begin forp: =i+1toj+1do f[i,j]: =max(f[i,j],f[p,j]+work(i,p-1)); forp: =j-1downtoi-1do f[i,j]: =max(f[i,j],f[i,p]+work(p+1,j)); end; end; procedureprint; begin writeln(f[1,n]); end; begin assign(input,'remove.in');reset(input); assign(output,'remove.out');rewrite(output); init; main; print; close(input);close(output); end. 3.俄罗斯方块 (game.pas/c/cpp) 【问题描述】 相信大家都玩过“俄罗斯方块”游戏吧,“俄罗斯方块”是一个有趣的电脑小游戏,现有一个有C列、行不受限定游戏平台,每一次下落的方块是下列的7个图形的一种: 在下落的过程中,游戏者可以作90、180或270度旋转,还可以左右移动,对于每一次方块落地,我们要求方块的每一部分都必须与地面(最底面或己落下的方块上表面)接触,例如,有一个宽度为6列的平台,每一列的初始高度(已经占用的方格数)分别为2,1,1,1,0和1。 编号为5的方块下落,有且仅有5种不同的落地方法: 现给出每一列的初始高度和下落方块的形状,请你编写一个程序,求出落地的方法总数,也就是落地后,地表面形成的不同的形状总数。 输入: 第一行为二个整数C和P,1≤C≤100,1≤P≤7,表示列数和下落方块的编号 第二行共有用一个空隔隔开的C个整数,每一个数字在0到100,之间(包含0和100),表示每一列的初始高度 输出: 输出为一个整数,表示落地的方法总数 样例数据 Input1 65 211101 Output1 5 Input2 51 00000 Output2 7 Input3 94 435465766 Output3 1 分析: 我们用编码序列表示下落方块的底部,比如编号为5的方块经过4种旋转得到4个序列: {1,1,1},{1,2},{2,1,2}和{2,1}。 如果序列A上每一个元素都加上同一个常数得到序列B,我们就称序列A和序列B是对应的,比如序列{2,1,2}与{5,4,5}对应,但不与{4,5,4}或{5,4}对应。 可以看出,当且仅当方块的序列与地面相对位置的高度形成的序列对应,那么这个方块能与地面能结合。 因此对于给定的方块和地面,我们只要简单地检查所有旋转所形成的可能的形状,这样我们就可以用枚举法求解。 此题比较简单,用枚举法解决,在实现中要考虑各种变换。 主要考查选手的基本的程序实现能力。 源程序: programgame; constMAXS=100; fin='game.in'; fout='game.out'; var v: array[1..MAXS]oflongint; s,f,i,count: longint; begin assign(input,fin);reset(input); assign(output,fout);rewrite(output); readln(s,f); if(f=4)or(f=7)then{如果是第四种和第七种,则变成第三种和第六种} begin dec(f); fori: =1tosdoread(v[s-i+1]); endelse fori: =1tosdoread(v[i]); count: =0; casefof 1: begin count: =s; fori: =1tos-3do if(v[i]=v[i+1])and(v[i]=v[i+2])and(v[i]=v[i+3])theninc(count); end; 2: begin fori: =1tos-1do ifv[i]=v[i+1]theninc(count); end; 3: begin fori: =1tos-1do ifv[i]=v[i+1]+1theninc(count); fori: =1tos-2do if(v[i]=v[i+1])and(v[i]=v[i+2]-1)theninc(count); end; 5: begin fori: =1tos-2do if((v[i]-v[i+1]=1)or(v[i]-v[i+1]=0))and(v[i]=v[i+2])theninc(count); fori: =1tos-1do ifabs(v[i]-v[i+1])=1theninc(count); end; 6: begin fori: =1tos-2do if(v[i+1]=v[i+2])and((v[i+1]-v[i]=1)or(v[i+1]-v[i]=0))theninc(count); fori: =1tos-1do if(v[i]=v[i+1])or(v[i]=v[i+1]+2)theninc(count); end; end; writeln(count); close(input); close(output); end. 4.燃烧木棍 (fire.pas/c/cpp) 【问题描述】 Tom是调皮的孩子,特别喜欢玩火,现在他手上有若干根长度分别为1和 的木棍,还有一张不能燃烧的平板,他把平板划分成长度为1的单元格,并标上座标。 然后按以下规则把平板上的木棍组成一个连通图: 木棍的两端必须放在单元格的顶点上。 即长度为1的木棍放在单元格的某一边上,长度为 的木棍放在单元格的对角线上。 Tom的点火规则是,只能从木棍的两端点火,而不能从木棍的中间点火。 如图,不能在A点点火,但在C点或B点点火都是充许的。 点火后,火会沿着木棍向前燃烧(每根都有自己的燃烧速度),并能点燃与它相接的其它木棍。 任务: 写一程序计算从哪里开始点火,使得燃烧的总时间最短,输出最短时间。 InputData 输入文件bete.in第一行为一个正整数N,表示组成图形的木棍数目,后面共有N行,每行5个数: X1Y1X2Y2T,其中(X1,Y1)和(X2,Y2)分别表示木棍两端的坐标,T表示木棍燃烧时间,是指从木棍的某一端点火燃烧到别一端,燃完所需的时间。 OutputData 输出文件bete.out是一个保留4位小数的实数,表示所有木棍完全燃烧的最少时间。 约束1≤n≤40 保证图形是连通的,所有的木棍长度都是1或 ,没有任何两根木棍重合. -200≤X1,Y1,X2,Y2≤200;0≤T≤107. 如果你的输出结果与标准答案相差小于0.001,则认为你的结果正确。 样例1 fire.in fire.out 解释 1 00111 1.0000 从任一端点火都行,燃烧时间都是1 样例2 fire.in fire.out 解释 5 00011 100110 00101 00111 22111 3.2500 在(0,0)位置点火 木棍1,3和4将被点燃,燃烧0.5分钟后,木棍2将被从中间点燃向两端燃烧,再过0.5分钟,木棍1,3,4将被完全燃烧,木棍5将被点燃并在1分钟后燃烧完(比木棍2早燃完)。 木棍2从中间向两端燃烧0.5分钟以后,变成两小段,每段的燃烧时间是4.5分钟。 但因为此时两小段木棍的另一端也同时被点燃,燃烧速度变成原来的两倍,还需2.25分钟的燃烧时间,所以总时间: 1+2.25=3.25 样例3 fire.in fire.out 解释 3 111210 122210 112250 35.0000 在(1,2)位置点火,木棍(11,12)和(12,22)将燃烧10分钟。 .最后一根木棍在10分钟后从两端被点燃,燃烧时间为25分钟。 分析: 在此题问题中,木棍构成的是一个连通图,如果我们直接构图处理比较复杂,我们对原问题进行转换,由于木棍与木棍之间只能在木棍的两端或中间相交。 我们把每根木棍拆分成两根相等的小木棍,这样,木棍的数量增加了一倍,原问题就转化为,木棍与木棍之间只能在木棍的两端相交,这样处理起来就比较方便。 我们以木棍为边,木棍与木棍之间的交点为顶点,构建一个连通图,问题变为寻找一个合适的顶点,使得点燃以后完全燃烧的时间最短。 很显然,燃烧时间等于点燃的顶点到图中最远点的时间,如下图 我们可以先求出某个点到其它所有点的最短时间,在这里我们可以使用Floyd’s算法求出任意两点之间的最短时间,时间复杂度为O(N3)。 注意,我们在这里用Floyd’s算法求的是第个点被点燃的时间,每个点被点燃,并不代表所有木棍都被完全燃烧,如上图。 求出从某个点到其它点的最短时间以后,余下的问题是检查每一边是否完全燃烧。 如果没有完全燃烧,求出剩余边燃烧所需最长时间。 对于燃烧时间为L的木棍,它的两端被点燃的时刻为T1和T2,如果T1=T2+L或者是T2=T1+L,那么燃烧到T1和T2的最大时刻,这根木棍己经完全燃烧。 如果T1与T2之间的时间差不等于L,那么就说明火是从不同的路径燃烧到这根木棍的两端。 火将从两端向中间燃烧,并在木棍内的某个点燃完,在简单情况中,如果是从两端同时点燃,燃烧时间为L/2。 更一般地,如果T1与T2不等,我们设一端是从0时刻点燃,另一端是从T时刻点燃,那么这根木棍的燃烧时间为T+(L-T)/2. 此题比较复杂,先要构图,并且要对原图形进行转换,再用Floyd’s算法求出任意两点之间的最少时间,最后还要检查所有的边是否燃烧,此题考查选手用图解决问题的能力,并且此题不能简单的套用Floyd’s算法,需要选手在解决问题中灵活运用经典算法。 源程序: ProgramMatches; Const MaxN=42;{N根木棍的端点} MaxG=2*MaxN+1;{拆分以后的最大顶点数} Infinity=MaxLongInt;{燃烧时间的最大值} VarN: Integer; Match: Array[1..MaxN]OfRecord{每根木棍构成边的信息: 端点座标和燃烧时间} X1,Y1,X2,Y2: Integer; Time: LongInt; End; NG: Integer; Vertex: Array[1..MaxG]OfRecord X,Y: Integer;{图的顶点信息} End; Edge,Distance: Array[1..MaxG,1..MaxG]OfLongInt; Res: Extended;{燃烧最少时间} ResX,ResY: Integer; ProcedureInit;{输入} VarI: Integer; Begin Read(N); ForI: =1ToNDo WithMatch[I]Do Read(X1,Y1,X2,Y2,Time); End; FunctionGetVertex(VX,VY: Integer): Integer; {intoarcenumarulvarfuluicucoordonateledatedacalipseste,estecreat} VarI: Integer; Begin ForI: =1ToNGDo WithVertex[I]Do If(X=VX)And(Y=VY)ThenBegin GetVertex: =I; Exit; End; Inc(NG);{Dacavarfulnuestegasit} WithVertex[NG]DoBegin X: =VX; Y: =VY; ForI: =1ToNG-1DoBegin Edge[I,NG]: =Infinity; Edge[NG,I]: =Infinity; End; Edge[NG,NG]: =0; End; GetVertex: =NG; End; ProcedureAddEdge(X1,Y1,X2,Y2: Integer;Time: Longint); {Functiaadaugamuchieintrevarfuri} VarA,B: Integer; Begin A: =GetVertex(X1,Y1); B: =GetVertex(X2,Y2); Edge[A,B]: =Time; Edge[B,A]: =Time; End; ProcedureBuildGraph;{构图} VarI: Integer; Begin NG: =0; ForI: =1ToNDo WithMatch[I]DoBegin AddEdge(X1*2,Y1*2,X1+X2,Y1+Y2,Time); AddEdge(X1+X2,Y1+Y2,X2*2,Y2*2,Time); End; End; ProcedureFindShortestPaths;{Floyd’s算法求任意两点之间的最短时间} VarK,I,J: Integer; Begin Distance: =Edge; ForK: =1ToNGDo ForI: =1ToNGDoIfDistance[I,K] ForJ: =1ToNGDoIfDistance[K,J] IfDistance[I,K]+Distance[K,J] Distance[I,J]: =Distance[I,K]+Distance[K,J]; End; FunctionBurnAt(At: Integer): Extended; VarI,J: Integer; Curent,ThisEdge: Extended; Begin Curent: =0; ForI: =1ToNGDoIfDistance[At,I]>CurentThenCurent: =Distance[At,I]; ForI: =1ToNGDo ForJ: =I+1ToNGDoIfEdge[I,J] If(Distance[At,I] (Distance[At,J] IfDistance[At,I] ThisEdge: =Distance[At,J]+(E
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- NOIP 提高 复赛 模拟 试题
![提示](https://static.bdocx.com/images/bang_tan.gif)