《2020年csp-j入门级复赛真题.docx》由会员分享,可在线阅读,更多相关《2020年csp-j入门级复赛真题.docx(16页珍藏版)》请在课桌文档上搜索。
1、2020年csp-j入门级复赛真题第一题:优秀的拆分(power)【题目描述】般来说,一个正整数可以拆分成若干个正整数的和。例如,I=It10=1+2+3+4等。对于正整数n的一种特定拆分,我们称它为“优秀的”,当且仅当在这种拆分下,n被分解为了若干个丕同的2的正整数次哥。注意,一个数X能被表示成2的正整数次耨,当且仅当X能通过正整数个2相乘在一起得到。例如,10=8+2=23+21是一个优秀的拆分。但是,7=4+2+1=2+21+20就不是一个优秀的拆分,因为1不是2的正整数次鼻。现在,给定正整数n,你需要判断这个数的所有拆分中,是否存在优秀的拆分。若存在,请你给出具体的拆分方案。【输入格式
2、】输入文件名为power.in.输入文件只有一行,一个正整数n,代表需要判断的数。【输出格式】输出文件名为power.out.如果这个数的所有拆分中,存在优秀的拆分。那么,你需要从大到小输出这个拆分中的每一个数,相邻两个数之间用一个空格隔开。可以证明,在规定了拆分数字的顺序后,该拆分方案是唯一的。若不存在优秀的拆分,输出(不包含双引号)。【样例1输入】6【样例1输出】42【样例1解释】6=4+2=22+21是一个优秀的拆分。注意,6=2+2+2不是一个优秀的拆分,因为拆分成的3个数不满足每个数互不相同。【样例2输入】7【样例2输出】-1【样例3见选手目录下的powerpower3.in与pow
3、erpower3.ans【数据范围与提示】对于20%的数据,n=10.对于另外20%的数据,保证n为奇数。对于另外20%的数据,保证n为2的正整数次募。对于80%的数据,n=1024.对于Io0%的数据,l=ll7.题目解析:一个数本来就可以拆分成2的正整数次鬲,因为利用它的二进制即可得到。例如:6的二进制是IlOt分别代表22,21,20所以6可以看成22+21=4+2。对n进行二进制分解,然后倒序输出即可。参考程序:#include#include#includeusingnamespacestd;intn;intmain()(cin;if(n%2=1)cout=1;i-)coutai,;
4、)returnO;)零一点评:本题难度显著高于2019,2018,2017年的第一题。没有联想到二进制转化的同学可能会被卡住。一旦联想到,就是一个【入门】级题目。骗分方法:第一个20%:对每个n,打表第二个20%:根据题意,不存在,直接输出-1第三个20%:它的拆分就是它本身,直接输出n本身【数据范围与提示】对于2096的数据,n=10.对于另外20%的数据,保证n为奇数。对于另外20%的数据,保证n为2的正整数次帚。对于80%的数据,n=1024.对于Ioo骊的数据,l=n=IXloA7.第二题直播获奖(IiVe)【题目描述】NoI2130即将举行。为了增加观赏性,CCF决定逐一评出每个选手
5、的成绩,并直播即时的获奖分数线。本次竞赛的获奖率为w%,即当前排名前W的选手的最低成绩就是即时的分数线。更具体地,若当前已评出了P个选手的成绩,则当前计划获奖人数为max(1,p*w)1其中W是获奖百分比,冈表示对X向下取整max(xty)表示X和y中较大的数。如有选手成绩相同,则所有成绩并列的选手都能获奖,因此实际获奖人数可能比计划中多。作为评测组的技术人员,请你帮CCF写一个直播程序。【输入格式】输入文件名为live.in.第1行两个正整数n,W1分别代表选手总数与获奖率。第2行有n个非负整数,依次代表逐一评出的选手成绩。【输出格式】输出文件名为live.out.只有一行,包含n个非负整数
6、,依次代表选手成绩逐一评出后,即时的获奖分数线。相邻两个整数间用一个空格分隔。【样例1输入】10602003004005006006000300200100【样例1输出】200300400400400500400400300300【数据范围与提示】对于20%的数据,n=10对于另外20%的数据,保证n为奇数。对于另外20%的数据,保证n为2的正整数次帚。对于80%的数据,n=1024对于IO0%的数据,l=n=107【数据范围与提示】测试点编号n1-3=1046=5007-10=200011-17=1000018-20=100000对于所有测试点,每个选手的成绩均为不超过600的非负整数,获奖
7、百分比W是一个正整数目l=w=99.在计算计划获奖人数时,如用浮点类型的变量(如C/C+中的floatd。UbePaSCal中的real,double,extended)存储获奖比例w%,则计算5x60%时的结果可能为3.000001,也可能为2.999999,向下取整后的结果不确定。因此,建议仅使用整型变量,以计算出准确值。题目解析:50分程序:对于每个选手,把之前的数据进行Sort排序,选择max(LpXw%J)人处的分数。时间复杂度约为0(2)o100分程序:观察到数据范围里成绩在600以内,因此可以变sort排序为桶排序。准备600个桶,每个选手处,把他分数对应的桶里的个数+。然后从第
8、600号桶倒序循环到1号桶,进行人数统计,输出max(l,pM6J)人处的分数。时间复杂度为O(600n)o零一点评:本题延续了2019年第二题的风格:除了基础代码能力,增加了对时间复杂度的考察。如果时间复杂度过关,那么难度要弱于2019年的公交换乘。另外本题对于浮点数运算的考察也是一个易错点。#include#include#includeusingnamespacestd;intn1w1b605;intmain()(cinnw;for(inti=1;iv;bv+;intct=max(l,i*w/100);intk=600,sum=0;while(k=0)if(sum+bkent)sum+=
9、bk;k-;elsecoutk,;break;)return0;)第三题表达式(expr)【题目描述】小c热衷于学习数理逻辑。有一天,他发现了一种特别的逻辑表达式。在这种逻辑表达式中,所有操作数都是变量,且它们的取值只能为。或L运算从左往右进行。如果表达式中有括号,则先计算括号内的子表达式的值。特别的,这种表达式有且仅有以下几种运算:1,与运算:a&b,当且仅当a和b的值都为1时,该表达式的值为It其余情况该表达式的值为02,或运算:ab,当且仅当a和b的值都为O时,该表达式的值为0,其余情况该表达式的值为1.3,取反运算:!a。当且仅当a的值为。时,该表达式的值为1,其余情况该表达式的值为0
10、.小C想知道,给定一个逻辑表达式和其中每一个操作数的初始取值后,再取反某一个操作数的值时,原表达式的值为多少。为了化简对表达式的处理,我们有如下约定:表达式将采用后缀表达式的方式输入。后缀表达式的定义如下:1.如果E是一个操作数,则E的后缀表达式是它本身。2,如果E是ElOPE2形式的表达式,其中。P是任何二元操作符,且优先级不高于El、E2中括号外的操作符,则E的后缀式为ElE2op,其中El、E2分别为El、E2的后缀式。3,如果E是(El)形式的表达式,则El的后缀式就是E的后缀式。同时为了方便,输入中:a)与运算符(&)、或运算符(I).取反运算符的左右均有一个空格,但表达式末尾没有空
11、格。b)操作数由小写字母X与一个正整数拼接而成,正整数表示这个变量的下标。例如:xl,表示下标为10的变量XlO0数据保证每个变量在表达式中出现恰好一次。【输入格式】输入文件名为expr.in.第一行包含一个字符串S1表示上文描述的表达式。第二行包含一个正整数n,表示表达式中变量的数量。表达式中变量的下标为L2,-ln第三行包含n个整数,第i个整数表示变量Xi的初值。第四行包含一个正整数q,表示询问的个数。接下来q行,每行一个正整数,表示需要取反的变量的下标。注意,每一个询问的修改都是临时的,即之前询问中的修改不会对后续的询问造成影响。数据保证输入的表达式合法。变量的初值为。或L【输出格式】输
12、出文件名为expr.out.输出一共有q行,每行一个。或L表示该询问下表达式的值。【样例1输入】xlx2&x3I31013123【样例1输出】110【样例I解释】该后缀表达式的中缀表达式形式为(xl&x2)Ix3对于第一次询问,将xl的值取反。此时,三个操作数对应的赋值依次为0,Ot1,原表达式的值为(0&0)11=1.对于第二次询问,将x2的值取反。此时,三个操作数对应的赋值依次为1,1,1,原表达式的值为(1&1)|1=1.对于第三次询问,将x3的值取反。此时,三个操作数对应的赋值依次为LOt0,原表达式的值为(1&0)I0=0.【样例2输入】xl!x2x4Ix3x5!&!&5OlOll3
13、135【样例2输出】011【样例2解释】该表达式的中缀表达式形式为(Ixl)&(!(2x4)&(x3&(!x5)0【样例3见选手目录下的eprlexpr3.in与exprexpr3.ans.【数据范围与提示】对于20%的数据,表达式中有且仅有与运算(&)或者或运算对于另外30%的数据,s=IoO0,q=10001n=1000.对于另外20%的数据,变量的初值全为0或全为1.对于Io0%的数据,K=sl=lxl06,K=q=ll05,2=n=2个0,那么无论变哪个数值,因为只能变一个值,那么&的最终结果一定是0;如果n个数里有1个0,如果这个0正好就是输入的那个位置,那么结果为1,否则结果是0。
14、如果只有I运算:如果n个数里有=2个L那么无论变哪个数值,因为只能变一个值,那么I的最终结果一定是1;如果n个数里有1个1,如果这个1正好就是输入的那个位置,那么结果为0,否则结果是1。30分程序:首先需要对后缀表达式的处理熟悉:遇到数字,入栈;遇到运算符,取出栈顶的两个数字,进行相应运算符的运算,再把运算结果重新入栈。最终栈里剩下的那个数字即为最终结果。对输入字符串,分离出数字,运算符,按照上述描述利用栈进行模拟即可。50分程序:20分程序+30分程序。100分程序:利用&运算和I运算的性质进行优化。&运算里,一方如果是0,那么另一方无论如何变化,结果都不会改变。同样的I运算里,一方如果是L
15、那么另一方无论如何变化,结果都不会改变。可以建立表达式的二叉树,然后看看哪些Xi的变化会影响结果。例如,下图中根是&运算.红色结点原始结果是0,绿色是L那么绿色结点以下的Xi无论怎么变化,都不会改变最终结果是0这个结果。因此只递归到红色结点,绿色停止递归。若红色原始结果是0,绿色也是0,那么它们以下的任何Xi变化都不会改变最终结果,因为一方变化,另一方肯定还是0。因此不继续递归下去。若红色原始结果是L绿色是0,那么红色以下的任何Xi改变都不会改变最终结果。因此只递归到绿色结点。若红色和绿色都为L那么它们以下的Xi的改变都有可能影响到最终结果,因此递归到左右结点O如果上述过程中能递归到某个Xi,
16、说明这个Xi的改变,就会改变最终结果。若某个Xi不能被递归到,说明它的改变并不能影响最终结果。如何建立表达式二叉树树?例如序列x2x3xl&!|。x2,x3,xl依次入栈,同时新建二叉树结点。接着遇到&,新建结点,并且把栈顶的两个结点当成这个新建结点的左右子树。遇到I同样建立新结点,同时把栈顶当做它的左子树。遇到新建结点,并且把栈顶的两个结点当成这个新建结点的左右子树。零一点评:本题第一个20%的样例非常具有迷惑性,很多同学以为是&和I混杂,实际是单纯只有&,或者单纯只有如果读题读对了,20分非常容易骗得。接下来30%的数据,需要懂得栈和后缀表达式的原理,并且熟悉字符串的操作。对于基础算法掌握
17、好的同学比较容易骗到。100%的思路是全场最难想的,需要对位运算有很强的洞悉能力,或者练习到过类似的高级数据结构的题目。20分程序#include#include#includeusingnamespacestd;strings;intn,a1000005,q;intmain()(getline(cin1s);intcnt=0;cin;for(inti=1;iai;if(ai=0)cnt+;)if(s.find(&)!=-1)cinq;for(inti=1;ix;if(cnt=2)coutOendl;elseif(ct=1&ax=O)cout1endl;elsecoutOq;for(inti=
18、1;ix;if(n-cnt=2)cout1endl;elseif(n-cnt=1&ax=1)coutOendl;elsecout1endl;)returnO;)30分程序#include#include#includeusingnamespacestd;stringss;intn1a10000051q;itz1000005,top;voidrev(intx)if(a=O)ax=1;elseax=0;)intmain()(getline(cin1ss);cin;for(inti=1;iai;)cinq;for(inti=1;ix;rev(x);/计算后缀表达式的值top=0;strings=ss
19、;s+=,;while(s.find()!=-1)stringb=s.substr(O,s.find();s.erase(0,s.find()+1);if(b.size()=0)continue;if(b0=,x)intvalue=0;for(intj=1;jb.size();j+)value=value*10+bj-01;)z+top=avalue;elseif(b0=,!)ztop=!ztop;elseif(b0=&)intxl=ztop-;intx2=ztop-;z+top=xl&x2;elseif(b0=T)intxl=ztop-;intx2=ztop-;z+top=xlIx2;cou
20、tzlendl;rev(x);)return0;)100分程序#include#include#includeusingnamespacestd;intn1a10000051q;itz1000005,top;intent;structtreeintI;intr;intv;t1000005;boolf1000005;boolchange1000005;boolcalc(inti)计算每个二叉树结点的运算结果if(ti,v=O)/数值结点W=ati.v;returnfi;)boolxl=calc(ti.l);boolx2=calc(ti.r);if(ti,v=-1)fi=!xl;elseif(ti
21、.v=-2)fi=xl&2;elsefi=xlx2;returnfi;)voidaffect(iti)/看看i结点的运算会不会受左右孩子影响if(ti.v=O)/如果能递归到数值结点changeti.v=1;说明这个数值的变化会改变结果return;)if(ti.v=-1)affect(ti.l);/!运算elseif(ti.v=-2)&运算if(fti.l=1&fti.r=1)affect(ti.l);affect(ti.r);elseif(fti.l=O&fti.r=1)affect(ti.l);elseif(fti.l=1&fti.r=O)affect(ti.r);)else/I运算if
22、(fti.l=O&fti.r=O)affect(ti.l);affect(ti.r);elseif(fti.l=O&fti.r=1)affect(ti.r);elseif(fti,l=1&fti.r=O)affect(ti.l);)intmain()(charch;while(ch=getchar()!=n,)intv;if(ch=x)+ent;新建表达式树的结点scanf(%d,v);tcnt.v=v;z+top=ent;)elseif(ch=)cotiue;else+ent;新建表达式树的结点if(ch=!,)tcnt.l=ztop-;tcnt.v=-1;elseif(ch=&)tcnt.
23、l=ztop-;tct.r=ztop-;tcnt.v=-2;elsetct.l=ztop-;tcnt.r=ztop-;tcnt.v=-3;)z+top=ent;)scanf(%d,n);for(inti=l;iq;for(inti=1;ix;if(change)cout!fcntedl;elsecoutfcntendl;)returnO;第四题:方格取数(number)【题目描述】设有nxm的方格图,每个方格中都有一个整数。现有一只小熊,想从图的左上角走到右下角,每一步只能向上、向下或向右走一格,并且不能重复经过已经走过的方格,也不能走出边界。小熊会取走所有经过的方格中的整数,求它能取到的整数
24、之和的最大值。【输入格式】输入文件名为number.in.第1行两个正整数n,m.接下来n行每行m个整数,依次代表每个方格中的整数。【输出格式】输入文件名为umber.out.一个整数,表示小熊能取到的整数之和的最大值。【样例1输入】341-1322-14-1-22-3-1【样例1输出】9【样例2输入】25- 1-1-3-2-7- 2-1-4-1-2【样例2输出】- 10按上述走法,取到的数之和为(-1)+(-1)+(-3)+(-2)+(-1)+(-2)=-10,可以证明为最大值。因此,请注意,取到的数之和的最大值也可能是负数。【样例3见选手目录下的numbernumber3.in与numbe
25、rnumber3,ans【数据范围与提示】对于20%的数据,n,m=5对于40%的数据,n,m=50.对于70%的数据,n,m=300.对于Io0%的数据,l=n,m70分采用前缀和非常好优化,基础前缀和算法掌握好的同学只要得到40分,不难得70分。100分的思路属于更高级的动态规划的优化思路,不容易想到,需要有大量动态规划实战经验。20分程序#include#include#includeusingnamespacestd;intn,m1a10051005,used10051005,ans=0x80000000;intdi4=0,0,l,-l);intdj4=0,l,0.0;voidgo(i
26、nti,intj,ints)if(i=n&j=m)ans=max(as,s);return;)for(intk=1;k=1&newi=1&newjm;for(inti=1;i=n;i+)for(intj=1;jaij;)usedll=1;g(l.1.all);coutans;returnO;)40分程序/没有使用前缀和预计40分#include#include#includeusingnamespacestd;intn,m,a10051005;intf10051005;intmain()(cinnm;for(inti=1;i=n;i+)for(intj=1;jaij;fij=0x8000000
27、0;)for(inti=1;i=;i+)intsum=0;for(intI=1;I=i;I+)sum+=all;)fil=sum;)for(intj=2;j=m;j+)for(inti=1;ii行,到达(i,j)for(intk=1;k=i;k+)intsum=0;for(intl=k;li行,到达(i,j)for(intk=i+1;k=n;k+)intsum=0;for(intI=i;I=k;I+)sum+=alj;)fij=max(fiD.fkQ-l+sum);)coutfnm;return0;)70分程序#include#include#includeusingnamespacestd;
28、intn,m,a10051005tpre10051005;intf10051005;intmain()(cinnm;for(inti=1;i=n;i+)for(intj=1;jaij;fij=0x80000000;)for(intj=1;j=m;j+)for(inti=1;i=n;i+)pre11=pre11i-l+ai11;)for(inti=1;i=n;i+)f11l=preli;)for(intj=2;j=m;j+)for(inti=1;ii行,到达(i,j)for(intk=1;ki行的区间和intsum=preji-prek-l;fij=max(fiDtfkQ-l+sum);)从(k
29、,j-l)开始走第j列的k行-i行,到达(i,j)for(intk=i+1;kk行的区间和intsum=prejk-preji-l;fi11=max(fiO,fkQ-l+sum);)coutfnm;returnO;)100分程序#include#include#include#defineIllonglongintusingnamespacestd;Iln,m1a10051005;Ilf10051005;Ilfl10051005,fu100510051fd10051005;intmain()cinm;for(inti=1;i=;i+)for(intj=1;jaij;)for(inti=O;i=
30、+l;i+)for(intj=O;j=m+1;j+)fij=fi01=fu11D=fdiQ=-lel8;)for(inti=1;i=;i+)Ilsum=O;for(intk=1;k=i;k+)sum+=akl;fil=sum;)for(intj=2;j=m;j+)for(inti=1;iD-Uai11;)for(inti=2;i=1;i-)fdi11=max(fli+lD,fdi+lD)+aij;)for(inti=1;i=n;i+)fiO=max(fliU,fuiD);fij=max(fiD,fdiD);)coutfnm;returnO;)总点评:第一题,显著难于17、18、19年第一题。往
31、年第一题对于二三等奖区分度不高,希望今年有好的划线。第二题,果然延续了去年第二题公交换乘对于时间复杂度的考察,但是代码实现起来比18、19年简单一些。第三题,第一个20%的样例描述十分具有迷惑性,否则非常容易骗分。另外模拟栈实现后缀表达式属于基础算法,无论在初赛备战还是知识点学习时都涉及过。只是因为有字符串操作,需要有熟练的代码实现能力。100分的算法属于本场最难,需要很好的洞察力和数据结构实战能力,对高分段会有一定区分度。第四题,第一个20%的数据采用经典基础搜索算法即可骗到分,很久没有这么干脆的考察模版搜索问题了,对于虽然不精通但认真学过算法的同学很友好。剩下的思路需要动态规划算法,且要有较好的实战能力,卡出只会模版算法的同学,对于能力高的同学有一定的区分度。原文链接: