NOIP 2013 解题报告

合集下载

Noip_2013_提高组_Day2_解题报告

Noip_2013_提高组_Day2_解题报告

第二题:花匠(动态规划)1.令S[i][1]表示以i为结尾,且降序到达a[i]的最长抖动序列长度;令S[i][0]表示以i为结尾,且升序到达a[i]的最长抖动序列长度。

依然设数组S[i][0/1],但考虑如下递推公式:(1)a[i+1]>a[i]:S[i+1][0]=max(S[i][1]+1,S[i][0]);S[i+1][1]=S[i][1];(2)a[i+1]<a[i]:S[i+1][0]=S[i][0];S[i+1][1]=max(S[i][0]+1,S[i][1]);(3)a[i+1]= =a[i]:S[i+1][0]=S[i][0];S[i+1][1]=S[i][1];S[1][0]=S[1][1]=1.算法优化后,再一次编写程序,O(n)的时间复杂度,当然是顺利AC了,代码如下:2.这道题明显可以用类似最长上升子序列的动态规划求解,易得思路如下:用f(i,0)表示以i为结尾的且最后一段上升的子序列最大长度,f(i,1)表示表示以i 为结尾的且最后一段下降的子序列最大长度,那么答案明显就是max{f(i,0),f(i,1)} 方程:f(i,0)=max{f(j,1)}+1 0<=j<i且h[j]<h[i]f(i,1)=max{f(j,0)}+1 0<=j<i且h[j]>h[i]边界:f(0,0)=f(0,1)=0如果直接DP毫无疑问复杂度是O(n^2),会TLE,但是,考虑到我们每次取最值时候取得都是一个区间里的数,如f(i,0)=max{f(j,1)}+1 0<=j<i且h[j]<h[i]取得就是区间[0,h[i]-1]里的最值,所以可以使用线段树或者是BIT(树状数组)来优化,这样复杂度就是O(n log n),可以过全部数据。

这道题还有一个解法,直接求拐点数目,然后就可以神奇的做到O(n)了,由于我找不到满意的证明,就不发上来了。

NOIP2013年普及组复赛真题解析

NOIP2013年普及组复赛真题解析

NOIP2013年普及组复赛真题解析T1 计数问题解析:对于100%的数据,1≤ n ≤ 1,000,000,0 ≤ x ≤ 9。

枚举每个数的每一位就行。

程序:include<cstdio>#include<iostream>using namespace std;int main(){int n,x;cin>>n>>x;int i,c=0;for(i=1;i<=n;i++){int a=i;while(a!=0){if(a%10==x)c++;a/=10;}}cout<<c;return 0;}===================================================T2 表达式求值解析:对于30%的数据,0≤表达式中加法运算符和乘法运算符的总数≤100;对于80%的数据,0≤表达式中加法运算符和乘法运算符的总数≤1000;对于100%的数据,0≤表达式中加法运算符和乘法运算符的总数≤100000。

程序:#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;char last;char c;int x=0;int a=0,b=1;int sum=0;int main(){int i,j;bool flag=1;do{if(cin>>c);else{flag=0;c='+';//相当于在整个串最后补个+号,以完成全部运算}if(c>='0' && c<='9')x=x*10+c-'0';//读取数else{a=x;//如果读到的不是数字,把之前读到的数存起来x=0;//初始化}if(c=='*'){//处理乘号,方法是先记下这个数,下次读到乘号再计算last=1;b=(a*b)%10000;//有连续乘号时,累乘}if(c=='+'){if(last){//上一个是乘号的情况a=(a*b)%10000;sum=(sum+a)%10000;b=1;last=0;}else sum+=a;//上一个是加号的情况}}while(flag==1);printf("%d",sum%10000);return 0;}===================================================T3解析:Case 1:小朋友的特征值分别为1、3、6、10、15,分数分别为1、2、5、11、21,最大值21对997 的模是21。

信息学奥赛NOIP普和组历届试题分析报告

信息学奥赛NOIP普和组历届试题分析报告
普及组一般考查的动态规划:01背包,最长上升子序 列,一些简单的线性动规。
采药 (noip2005普及组第三题)
辰辰是个天资聪颖的孩子,他的梦想是成为世 界上最伟大的医师。为此,他想拜附近最有威 望的医师为师。医师为了判断他的资质,给他 出了一个难题。医师把他带到一个到处都是草 药的山洞里对他说:“孩子,这个山洞里有一 些不同的草药,采每一株都需要一些时间,每 一株也有它自身的价值。我会给你一段时间, 在这段时间里,你可以采到一些草药。如果你 是一个聪明的孩子,你应该可以让采到的草药 的总价值最大。”
试计算在区间1到n的所有整数中,数字x(0≤x≤9) 共出现了多少次? 例如,在1到11中,即在1、2、3、4、5、6、7、8、 9、10、11中,数字1出现了4次。
输入:
输入共1行,包含2个整数n、x,之间用一个空格隔 开。 输出:
输出共1行,包含一个整数,表示x出现的次数。 输入示例: 11 1 输出示例: 4 其他说明:
输入 输入共1行,一个整数N。
输出 输出共1行,一个整数,表示反转后的新数。
样例输入
123 样例输出
321
统计单词个数 (noip2011普及组第二题)
一般的文本编辑器都有查找单词的功能,该功 能可以快速定位特定单词在文章中的位置,有 的还能统计出特定单词在文章中出现的次数。 现在,请你编程实现这一功能,具体要求 是:给定一个单词,请你输出它在给定的文章 中出现的次数和第一次出现的位置。注意:匹 配单词时,不区分大小写,但要求完全匹配, 即给定单词必须与文章中的某一独立单词在不 区分大小写的情况下完全相同(参见样例1), 如果给定单词仅是文章中某一单词的一部分则 不算匹配(参见样例2)。
对于100%的数据,3 ≤ n ≤ 100 测验题给出的正整数大小不超过10,000。

NOIP2013复赛模拟8解题报告

NOIP2013复赛模拟8解题报告

NOIP2008模拟试题1(4P24)普及组1.报数(read.pas/c/cpp) OIP2010模拟试题4(4P36)[题目描述]CG同学又弄到一批新牛,新牛到了农场以后,首先要学习汉语,数的朗读成为新牛的一个难题,朗读绝对值小于10亿的数。

新牛们知道汉语中有如下的读数规则:1.首先读符号位,然后读整数部分,整数部分之后可能出现小数点,如果有小数部分则小数点一定出现,并且读出小数点之后读小数部分。

2.符号位的读法是:⑴正数,不论正号”+”是否出现,都不必读出符号位;⑵负数的最左边的符号是”-“,读成”负”(以“F”来表示“负”)。

3.整数部分的读法是:⑴如果整数部分不存在或者整数部分全是零则直接读成“零”(以“0”来表示“零”);⑵否则从整数部分中最左边的非零数字开始读起,然后以十、百、千、万、亿(分别以”S”、”B”、”Q”、”W”、“Y”来表示)等数量单位来拼读整数部分。

4.整数部分中:⑴每一个非零数字都必须结合各个相应的数量单位读出来;⑵每一段连续的“零”只能读成一个“零”,但是某一段连续的“零”的左侧或者右侧不存在非零数字(这里只考虑整数部分)则这一段“零”不应该读出来;5.如果有小数部分,则首先读“点”(以“D”来表示“点”),然后从左至右有顺序地读出各个小数位。

在读小数部分的时候不可以使用十、百、千、万、亿等数量单位;但是小数部分的每一个数字都需要读出来,连续的零不可以读成一个“零”,而应该分别读出。

6.如果数中有小数点而没有小数部分,则不应该把小数点读出来。

例如:-0020030004.567应该读成”F2Q03W04D567”,000.89应该读成”0D89”。

请你编写程序帮助新牛把给定的数正确地读出来。

[输入数据]输入文件仅一行,存放了一个数(不超过50字符),其绝对值小于10亿.[输出数据]输出文件仅一行,输出这个数的正确读法。

[样例输入]-0020030004.567[样例输出]F2Q03W04D567program cz;varst,s,t:string;p,i:integer;beginassign(input,'read.in');reset(input);assign(output,'read.out');rewrite(output);readln(st);if st[1]='-' then begindelete(st,1,1);i:=1;while (i<length(st)) do beginif (st[i]<>'0') then beginwrite('F');break;end;inc(i);end;end;p:=pos('.',st);if (p=0) then p:=length(st);i:=1;while (st[i]='0') and (i+1<p) doinc(i);delete(st,1,i-1);p:=pos('.',st)-1;if (p=-1) then p:=length(st);s:='';i:=(p-1) mod 4+1;while (i>0) and (i<=p) do begint:='';if (i>3) thenif (st[i-3]>'0') thent:=t+st[i-3]+'Q'else if (s<>'') and (s[length(s)]<>'0') thent:=t+'0';if (i>2) thenif (st[i-2]>'0') thent:=t+st[i-2]+'B'else if (t<>'') and (t[length(t)]<>'0') thent:=t+'0';if (i>1) thenif (st[i-1]>'0') thent:=t+st[i-1]+'S'else if (t<>'')and(t[length(t)]<>'0') thent:=t+'0';if (i>0) thenif (st[i]>'0') then t:=t+st[i]+'';if (t[length(t)]='0') then delete(t,length(t),1); if (t<>'') then begins:=s+t;case (p-i) div 4 of1:s:=s+'W';2:s:=s+'Y';end;end;inc(i,4);end;if (s='') then s:='0';write(s);if (pos('.',st)>0)and(length(st)>pos('.',st)) thenwrite('D',copy(st,p+2,length(st)-p-1));writeln;close(input);close(output);end.2.背单词(words)源程序名:words.pas/c/cpp输入文件名:word.in输出文件名:word.out时限:1秒问题描述:英语四级考试临近了,小Y却发现他已经把以前学的单词几乎忘光了。

NOIP2013参赛总结

NOIP2013参赛总结

NOIP2013参赛总结安阳市七中常可一、题解1、count这道题其实并不难,不过是简单的模拟。

那些做不出来的真不知道是怎么学的。

程序:program count;vars:string;c:char;i,j,n,k,sum:longint;beginassign(input,'count.in');reset(input);assign(output,'count.out');rewrite(output);readln(n,j);c:=chr(j+48);for i:=1 to n dobeginstr(i,s);for k:=1 to length(s) do if s[k]=c then inc(sum);end;writeln(sum);close(input);close(output);end.我的程序采用了字符串,这样可以使程序稍短一些,不过不用的话也没有问题,大家可以自己想想。

2、expr这道题不算简单,和前几年的相比还是有些难度的,标准算法是栈,当然也有很多其他的方法。

一种比较好理解的是:从头开始搜索字符串,发现“+”的话把之前(我们这里的意思是从上一个加号到这一个加号,都不含加号)的字符串进行乘法运算。

由于这个字串里都是乘法运算,只需类似于第一步处理加号时的运算,在搜到乘号时乘上两乘号之间的数即可。

为了防止奇葩的数据,我们要在字符串后加上一个“+”,在每个加号前都加上一个“*”。

举个例子吧:1*2*3*4这个字串里没有加号,程序会因搜不到加号而得不出结果。

因此,要先在末尾加一个“+”,变成这样:1*2*3*4+这样程序搜到加号后,就会正常的运算。

乘号的道理是一样的。

接下来我们模拟一下程序的执行过程(以样例为标准):1+1234567890*11、添加号,变成1+1234567890*1+2、添乘号,变成1*+1234567890*1*+3、搜到第一个加号,加号前的字串是1*,乘法运算得到1,累加变量+14、搜到第二个加号,加号前的字串是1234567890*1*,乘法运算得到7890,累加变量+78905、结束,输出累加变量7891。

NOIP2013普及组第二题解题报告(汇文客原创)

NOIP2013普及组第二题解题报告(汇文客原创)

2.表达式求值(expr.cpp/c/pas)【问题描述】给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。

【输入】输入文件为expr.in。

输入仅有一行,为需要你计算的表达式,表达式中只包含数字、加法运算符“+”和乘法运算符“*”,且没有括号,所有参与运算的数字均为0到231-1之间的整数。

输入数据保证这一行只有0~ 9、+、*这12种字符。

【输出】输出文件名为expr.out。

输出只有一行,包含一个整数,表示这个表达式的值。

注意:当答案长度多于4位时,请只输出最后4位,前导0不输出。

【输入输出样例1】expr.in expr.out1+1*3+4 8【输入输出样例2】expr.in expr.out1+1234567890*1 7891【输入输出样例3】expr.in expr.out1+1000000003*1 4【输入输出样例说明】样例1计算的结果为8,直接输出8。

样例2计算的结果为1234567891,输出后4位,即7891。

样例3计算的结果为1000000004,输出后4位,即4。

【数据范围】对于30%的数据,0≤表达式中加法运算符和乘法运算符的总数≤100;对于80%的数据,0≤表达式中加法运算符和乘法运算符的总数≤1000;对于100%的数据,0≤表达式中加法运算符和乘法运算符的总数≤100000。

这道题我看了一下,全市一百三十多人中,得一百分的只有三十多人,二十来人得了八九十分,其余的,绝大多数只有一二十分。

其实,这题并不难,只是烦些,算法及其实现有很多种。

作为两校中唯一一个此题全过的,我希望能与大家分享我的思路与算法。

初看这个题目,第一反应是字符串处理+高精度。

我是一个水货,这两方面非常不熟,当时就懵了。

回过神后,再仔细看题,发现表达式内的数据都不超过longint范围,且只要输出后四位,甚至不用高位补“0”,这才发现,此题其实挺简单的。

万变不离模拟法,我的算法出炉了。

[NOIP2013普及组]表达式求值

[NOIP2013普及组]表达式求值

[NOIP2013普及组]表达式求值[NOIP2013 普及组] 表达式求值给定⼀个只包含加法和乘法的算术表达式,请你编程计算表达式的值。

Input⼀⾏,为需要你计算的表达式,表达式中只包含数字、加法运算符“+”和乘法运算符“*”,且没有括号,所有参与运算的数字均为 int 范围内的正整数。

输⼊数据保证这⼀⾏只有0~9、+、*这12种字符。

Output⼀个整数,表⽰这个表达式的值。

直接上代码1 #include<iostream>2long long a[1000001],ha=1,sum=0;3char s[1000001];4using namespace std;5int main()6 {7 cin>>a[ha];8 a[ha]%=10000;9while(cin>>s[ha]>>a[++ha])10 {11 a[ha]%=10000;12 }13for(int i=ha;i>=1;i--)14 {15if(s[i]=='*')16 {17 a[i]*=a[i+1];18 a[i]%=10000;19 a[i+1]=0;20 }21 }22for(int i=1;i<=ha;i++)23 {24 sum+=a[i];25 sum%=10000;26 }27 cout<<sum;28return0;29 }啥意思呢,就是说他肯定是⼀个数接着⼀个字符再接着⼀个数,所以我们可以⽤:cin>>a[ha]; while(cin>>s[ha]>>a[++ha]那我们就不必把连续的⼏个数字字符组成⼀个数字这个恶⼼的东西了,之后我们把所有是乘数的压⼊栈中,两个两个的乘起来再相加,但是有⼀点需要注意⼀下就是其实并不是两两相乘,⽽是把我们得到的乘数两两分组,所以如果是两两相乘的话就会有很多值被新加了起来,所以对于两个数a[i]和a[i+1],相乘以后要让a[i+1]=0,这样下⼀次a[i+2]与a[i+1]如果相乘的话结果就是0,把它加进来也没啥影响。

Noip 2013 解题报告与参赛总结(PASCAL版)

Noip 2013 解题报告与参赛总结(PASCAL版)

Noip 2013 解题报告与参赛总结(pascal版)Noip结束也有一段时间了,网上也能查到很多解题报告。

虽然意义不大,但就当做是一点纪念吧,纪念我的第一次Noip。

(也很可能是最后一次了)Day1T1:应该不难看出是快速幂,只要把模板背过就可以轻松AC了。

属于例行水题。

T2:首先分析出移动的结果应使得列中最大的数在一起,次大的数在一起,以此类推。

因为要使化简下来的式子中两数之积最大。

然后就是YY出只要移动一列即可达到效果。

在此基础上处理发现实际是求序列中的逆序对数。

这也不难,方法有两种,一种是树状数组或线段树,另一种更简单,代码也更容易实现。

是通过归并排序求逆序对。

只需要在归并排序中加一个计数器ANS。

在“并”这一部分中记录一下即可,详细的看代码。

T3:本次考试中较难的一道题,SPFA可以做到40-60分。

并查集至少60分,听神犇说可以AC。

比较常用的方法是树链剖分或树上倍增。

还是说一下倍增吧(因为前一种太wo简bu单hui)。

首先跑一遍最大生成树。

(显然答案都只会是这棵树上边的权值)。

然后处理倍增的数据,要记录两个内容,一个是2^k的祖先,另一个是到祖先的路上最小权值。

我用的是DFS的方法。

每处理完一个节点就把信息传递给儿子。

中间顺便记录每个节点的深度。

倍增时先把询问的两个点处理到同一深度,然后同时向上倍增,直至倍增的祖先恰好相同,同时ANS不断记录更小的权值。

Day2T1:竟然不是数论!数学弱渣太感谢出题人了。

方法很简单,从左到右扫一遍,如果当前点的高度大于前一个,就直接给ANS 加上差值。

T2:竟然也是O(N)!欺骗蒟蒻的感情!和T1一样简单,YY出ANS即为拐点的个数。

记录拐点时注意一下,处理连续相同的等高的花。

T3:我认为是这次比赛最难的一道题,因为我写的时间最长。

(其实是自己代码能力太渣)。

这题看了大神的题解才算有点眉目,朴素的BFS在大数据上明显超时,如果你不满足于60分的话就要压缩搜索中的冗余状态。

c03-NOIP2013初赛答案解析

c03-NOIP2013初赛答案解析

一、单选题(15*1.5)1、A,一个字节有8个bit,32位整型变量占用4个字节,故选A。

2、A,二进制11.01转为十进制,(11.01)2 = 1*2+1+0*0.5+1*0.25 = (3.25)10 。

3、B,老和尚给小和尚讲的故事里边有故事本身,递归是函数内部调用函数本身,故选B,递归。

4、D,香农信息论鼻祖。

5、A,一定是满二叉树时拥有2个字节点的节点数最多,最下一层会有2013-1023=990个节点,于是倒数第二层会有990/2=495个节点有2个字节点,从第1层到倒数第三层共有1023-2^9=511个节点,且这些节点都是用2个子节点的节点,所以共有495+511=1006个,选A。

6、B,要使图不联通,只要其中某一个节点不连通即可,所有顶点度最少是3,所以最少需要删除3条边,选B。

7、D,此题最开始一眼扫到的时候脑子进水,跟学生将选B,O(n),实际上不是,计算F1需要1次,计算F2需要一次,计算Fn需要计算F(n-1)的次数加上F(n-2)的次数,所以其实就是计算Fn次,于是答案选择D,至于这个Fn到底是多大,数学上可以计算,它等于O(((1+sqrt(5))/2)^n).8、B,这个必须是B,没有什么好说的,中序遍历保证左边都是小于根的,右边都是大于根的,所以可以保证是一个有序序列。

9、D,A项6和17对11取余都是6发生冲突,B项10的平方和17的平方对11取余都是1发生冲突,C项6的两倍和17的两倍对11取余都是1发生冲突,D 项分别为1,2,3,4,不冲突。

10、D,IPV6地址是128位的。

谢谢网友指正!11、C,二分为6个和6个的顶点,此时边最多,有36条边。

12、B,我的学生几乎全选A去了,因为之前讲题只介绍过ASCII码,但是看到统一二字也应该想到Uni...前缀啊。

13、D,64位非零浮点数强制转换成32位浮点数,两个数会有大小上的细微差别,但不会发生符号变化,因为有专门的符号位。

noip2013飞扬的小鸟题解

noip2013飞扬的小鸟题解

noip2013day1T3飞扬的小鸟(评测平台:洛谷p1941)题目不讲了,大家都知道。

很显然的一个bfs,实则不然(实则我不会),那么就dp吧,但是怎么优化呢……心路过程:暴力没错,最朴素的暴力背包!对于ans[i][j],下降由ans[i-1][j+y[i-1]]转移而来(如果ans[i-1][j+y[i-1]]可到达);上升则要玄学操作(详见代码),高度达到m后无法再上升也是一个坑。

变量:#include<bits/stdc++.h>usingnamespace std;constint MAXX=1000000;struct obstacle{int p,l,h;//同题面}o[10010];//存储管道int n,m,k;int x[10010]={0},y[10010]={0};//上升和下降int ans[10010][1010]={0},f[10010][1010]={0},sum[10010]={}; //f表示这个点是否可飞到预处理(f[i][j]==-1则[i][j]为水管。

f[i][j]==1表示[i][j]可达)://忽略读入&读入优化&mycmpinlinevoid first(){sort(o+1,o+k+1,mycmp);//按位置排序for(int i=0;i<=n;++i)for(int j=0;j<=m;++j)ans[i][j]=MAXXfor(int i=0;i<=m;++i){f[0][i]=1;ans[0][i]=0;}for(int i=1;i<=k;++i){sum[o[i].p]=i;//记录到第i列有多少水管for(int j=0;j<=o[i].l;++j)f[o[i].p][j]=-1;for(int j=o[i].h;j<=m;++j)f[o[i].p][j]=-1;}return;}dp:inlinevoid dp(){for(int i=1;i<=n;++i){bool flag=false;//记录当前所在列能否飞过for(int j=1;j<m;++j){if(f[i][j]<0)continue;//如果当前点是管道直接continue if(f[i-1][j+y[i-1]]>0){//从可到达的点转移,下降处理f[i][j]=1;//记录当前点可到达ans[i][j]=min(ans[i][j],ans[i-1][j+y[i-1]]);flag=true;}for(int k=1;k*x[i-1]<=j;++k)//上升if(f[i-1][j-k*x[i-1]]>0){f[i][j]=1;s[i][j]=min(ans[i][j],ans[i-1][j-k*x[i-1]]+k); flag=true;}}if(f[i][m]>=0)for(int k=0;k<=m;++k)//顶部处理if(f[i-1][k]>0){//不用看了,意会就好f[i][m]=1;int temp;if((m-k)%x[i-1]==0)temp=ans[i-1][k]+(m-k)/x[i-1]; else temp=ans[i-1][k]+(m-k)/x[i-1]+1;if(k==m)temp=ans[i-1][k]+1;ans[i][m]=min(ans[i][m],temp);flag=true;}if(flag==false)print(i-1);}print(n);return;}输出:inlinevoid print(int place){if(place<n){printf("0\n");for(int i=place;i>=0;i--)if(sum[i]){//自行体会printf("%d",sum[i]);exit(0);}printf("0");exit(0);}int minn=MAXX;for(int i=1;i<=m;i++)if(f[n][i]==1)minn=min(ans,ans[n][i]);printf("1\n%d",minn);return;}光荣TLE优化终于,我意识到了,向上飞作为一个完全背包,ans[i][j]可以由ans[i][j-x[i-1]]+1转移而来,但是这样的话,暴力方案中的标记就会出问题:对于这张图片,假设x[i]=1,那么如果第i+1列有水管的点不去搜索,第i+1列就飞不到了……但是实际上可以点四次来飞到。

NOIp2013普及组解题报告

NOIp2013普及组解题报告

NOIp2013 普及组 解题报告
By 绍兴文理学院附中 任轩笛
NOIp2013 普及组 解题报告
By 绍兴文理学院附中 任轩笛
代码_算法一
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 var i,j,k,l,m,n,ToTm,ToTf:Longint; s,Ans:Ansistring; Tmp,Tmp1,Tmp2:Int64; Dis:array[' '..'@'] of Longint; Sm:array[0..200000] of Int64; sf:array[0..200000] of char; Function Math(c:char):Boolean; begin Exit((c>='0')and(c<='9')); End; Procedure Doit(S:Ansistring); var i,j,k:Longint; ch:char; Begin i:=1; While i<=Length(s) do Begin If Math(s[i]) then Begin Tmp:=0; While Math(s[i]) do Begin Tmp:=Tmp*10+ord(s[i])-48; Inc(i); End; Inc(ToTm);Sm[ToTM]:=Tmp mod 10000; End Else Begin ch:=s[i]; While Dis[sf[ToTf]]<=Dis[ch] do Begin Tmp1:=Sm[ToTm]; Tmp2:=Sm[ToTm-1]; If Sf[ToTf]='+' then Tmp:=Tmp1+Tmp2 Else Tmp:=Tmp1*Tmp2; Sm[ToTm-1]:=Tmp mod 10000; Sm[ToTm]:=0; Dec(ToTm); Sf[Totf]:=' '; Dec(ToTf); End; By 绍兴文理学院附中 任轩笛

2013NOIP初赛提高组精彩试题解析汇报

2013NOIP初赛提高组精彩试题解析汇报

19.2 十九届提高组一、单项选择题(共15题,每题1.5分,共计22.5分;每题有且仅有一个正确选项)1.一个32位整型变量占用( A )个字节。

A.4 B.8 C.32 D.1282.二进制数11.01在十进制下是( A )。

A.3.25 B.4.125 C.6.25 D.11.1253.下面的故事与( B )算法有着异曲同工之妙。

从前有座山,山里有座庙,庙里有个老和尚在给小和尚讲故事:“从前有座山,山里有座庙,庙里有个老和尚在给小和尚讲故事:‘从前有座山,山里有座庙,庙里有个老和尚在给小和尚讲故事…………………………’”A.枚举B.递归C.贪心D.分治4.1948年,(D )将热力学中的熵引入信息通信领域,标志着信息论研究的开端。

A.冯•诺伊曼(John von Neumann) B.图灵(Alan Turing)C.欧拉(Leonhard Euler)D.克劳德•香农(Claude Shannon)【分析】香农信息论鼻祖5.已知一棵二叉树有2013个节点,则其中至多有( A )个节点有2个子节点。

A.1006 B.1007 C.1023 D.1024【分析】(1)树根深度为0,深度为10的满二叉树节点总数2047;(2)本题树深为10的完全二叉树,与满二叉树相比少了34个节点,(3)深度为9的满二叉树节点总数量为1023;(4)1023-(34/2)=10066.在一个有向图中,如果任意两点之间都存在路径相连,则称其为连通图。

右图是一个有5个顶点、8条边的连通图。

若要使它不再是连通图,至少要删去其中的( B )条边。

A.2 B.3 C.4 D.5【分析】要使图不联通,只要其中某一个节点不连通即可,所有顶点度最少是3,所以最少需要删除3条边7.斐波那契数列的定义如下:F1=1,F2=1,F n=F n-1+F n-2(n≥3)。

如果用下面的函数计算斐波那契数列的第n项,则其时间复杂度为( D )。

「NOI2013」小Q的修炼解题报告

「NOI2013」小Q的修炼解题报告

「NOI2013」⼩Q的修炼解题报告第⼀次完整的做出⼀个提答,花了半个晚上+⼀个上午+半个下午总体来说太慢了对于此题,我认为的难点是观察数据并猜测性质和读⼊操作我隔⼀会就思考这个sb字符串读起来怎么这么⿇烦啊⾸先可以发现,这个所有的选择都之后往后⾛,就是个topo图task1,2,3观察到数据有形如s x x+11v 3 + c yv 4 + c yv 5 + c yv 6 + c yv 7 + c yv 8 + c yv 9 + c yv 10 + c yv 11 + c yv 12 + c y之类的东西,⽽且每个这样的循环后⾯有⼀个这样的东西i v 3 c 0 43 45v 1 - v 3i c 0 c 1 46 0v 1 + v 3v 3 - v 3i v 4 c 0 48 50v 1 - v 4i c 0 c 1 51 0v 1 + v 4v 4 - v 4...发现这个就是把正的数据加到1上,负的不变并清空这样就没法贪⼼或者dp了然后我们⼜发现循环长度很⼩,直接爆搜就⾏了代码搞丢了..S_1 要讨论⾛哪个循环S_2 直接爆搜S_3 发现⼜很多组,分组爆搜task4,5,6最开始对变量2有⼀个正的初值然后s 5 8v 2 - c 10v 1 + c 22750i c 0 c 1 8 0i v 2 c 9 9 10i c 0 c 1 14 0循环节长这样每次如果选择,会有⼀些跳转之类的发现2的初值⽐较⼩⽽且后⾯只会减考虑dpdp_{i,j}第i⾏第2个变量的值是j的时候最⼤的1然后模拟转移,记录路径就可以了#include <cstdio>#include <cstring>#include <algorithm>#define ll long longusing std::max;const int N=6010;int n,m;char op[5],t0[10],t1[10];int x0,x1,x2,x2;struct koito_yuukoito_yuu(int Op,int A,int B,int C){op=Op,a=A,b=B,c=C;} }yuu[N];struct node{int i,j,cho;node(){}node(int I,int J,int Cho){i=I,j=J,cho=Cho;}}pre[N][5010];ll dp[N][5010];int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%s",op);if(op[0]=='s'){tim[++k]=i;scanf("%d%d",&x1,&x2);yuu[i]=koito_yuu(1,x1,x2,0);}else if(op[0]=='v'){scanf("%d%s%s%d",&x0,t0,t1,&x1);yuu[i]=koito_yuu(2,x0,t1[0]=='+'?x1:-x1,0);}else{scanf("%s%d%s%d%d%d",t0,&x0,t1,&x1,&x2,&x3);if(t0[0]=='c'&&t1[0]=='c') yuu[i]=koito_yuu(3,x2,0,0);else if(t0[0]=='v'&&t1[0]=='c') yuu[i]=koito_yuu(4,x1,x2,x3); }}memset(dp,-0x3f,sizeof dp);int inf=dp[0][0];dp[0][0]=0;for(int i=1;i<=n;i++)for(int j=0;j<=5000;j++)if(dp[i-1][j]!=inf){if(yuu[i].op==1){int a=yuu[i].a,b=yuu[i].b;if(dp[a][j]<dp[i][j]){pre[a][j]=node(i,j,1);dp[a][j]=dp[i][j];}if(dp[b][j]<dp[i][j]){pre[b][j]=node(i,j,2);dp[b][j]=dp[i][j];}}else if(yuu[i].op==2){int a=yuu[i].a,b=yuu[i].b;if(a==1){if(dp[i+1][j]<dp[i][j]+b){pre[i+1][j]=node(i,j,0);dp[i+1][j]=dp[i][j]+b;}}else{int t=max(0,j+b);if(dp[i+1][t]<dp[i][j]){pre[i+1][t]=node(i,j,0);dp[i+1][t]=dp[i][j];}}}else if(yuu[i].op==3){int a=yuu[i].a;if(dp[a][j]<dp[i][j]){pre[a][j]=node(i,j,0);dp[a][j]=dp[i][j];}}else{int a=yuu[i].a,b=yuu[i].b,c=yuu[i].c;if(dp[b][j]<dp[i][j]){pre[b][j]=node(i,j,0);dp[b][j]=dp[i][j];}}else{if(dp[c][j]<dp[i][j]){pre[c][j]=node(i,j,0);dp[c][j]=dp[i][j];}}}}int tj=0;for(int i=1;i<=5000;i++)if(dp[n+1][tj]<dp[n+1][i])tj=i;int ti=n+1,cnt=0;while(ti){int tx=ti,ty=tj;ti=pre[tx][ty].i,tj=pre[tx][ty].j;if(pre[tx][ty].cho) ans[++cnt]=pre[tx][ty].cho;}for(int i=cnt;i;i--) printf("%d\n",ans[i]);return 0;}4,5,6都是⼀样的我本地跑6的时候居然开不下空间,还压了⼀会T_Ttask7,8,9,10这四个点就是前⾯的结合最开始的时候有2控制跳转的东西中间就是1,2,3点的循环差不多175⾏⼀个周期对周期压变量2的长度dp,每个周期⾥⾯爆搜说起来简单,写起来还是很⿇烦的我这个代码要把in的最后⼏⾏删掉Code:#include <cstdio>#include <cstring>#include <algorithm>#define ll long longusing std::max;using std::min;const int N=35010;int n,m;char op[5],t0[10],t1[10];int x0,x1,x2,x3;struct koito_yuu{int op,a,b,c;koito_yuu(){}koito_yuu(int Op,int A,int B,int C){op=Op,a=A,b=B,c=C;} }yuu[N];struct node{int i,j,cho;node(){}node(int I,int J,int Cho){i=I,j=J,cho=Cho;}}pre[N][1010];ll dp[N][1010];int Id[N],as[N][20],yuy[20][20],ct[N];ll solve(int id,int L,int R){int n=0;for(int i=L;i<=R;i++){if(yuu[i].op==1) ++n,yuy[n][0]=0;if(yuu[i].op==2) yuy[n][++yuy[n][0]]=yuu[i].b;if(yuu[i].op==3) break;}ll mx=-(1ll<<52);ct[id]=n;for(int s=0;s<1<<n;s++){if(s>>i-1&1){for(int j=1;j<=10;j++)sum[j]+=yuy[i][j];}ll su=0;for(int i=1;i<=10;i++) su+=sum[i]>0?sum[i]:-sum[i];if(mx<su){mx=su;for(int i=1;i<=n;i++)if(s>>i-1&1)as[id][i]=1;elseas[id][i]=2;}}return mx;}int endro[N],k,ans[N];int main(){freopen("train8.in","r",stdin);freopen("train8.out","w",stdout);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%s",op);if(op[0]=='s'){scanf("%d%d",&x1,&x2);x2=min(x2,n+1);yuu[i]=koito_yuu(1,x1,x2,0);}else if(op[0]=='v'){scanf("%d%s%s%d",&x0,t0,t1,&x1);if(t1[0]=='c'){yuu[i]=koito_yuu(2,x0,t0[0]=='+'?x1:-x1,0);}else{yuu[i]=koito_yuu(3,x0,0,x1);if(x0==12) endro[++k]=i;}}else{scanf("%s%d%s%d%d%d",t0,&x0,t1,&x1,&x2,&x3);x2=min(x2,n+1),x3=min(x3,n+1);if(t0[0]=='c'&&t1[0]=='c') yuu[i]=koito_yuu(4,x2,0,0);else if(t0[0]=='v'&&t1[0]=='c') yuu[i]=koito_yuu(5,x1,x2,x3); }}memset(dp,-0x3f,sizeof dp);dp[1][0]=0;for(int i=1;i<=k;i++){int tp;for(int j=endro[i-1]+1;;j++)if(yuu[j].op==1&&yuu[j].b-yuu[j].a==11){tp=j-1;break;}ll ad=solve(i,tp+1,endro[i]);for(int l=endro[i-1]+1;l<=tp;l++)for(int j=0;j<=1000;j++){if(yuu[l].op==1){int a=yuu[l].a,b=yuu[l].b;if(dp[a][j]<dp[l][j]){dp[a][j]=dp[l][j];pre[a][j]=node(l,j,1);}if(dp[b][j]<dp[l][j]){dp[b][j]=dp[l][j];pre[b][j]=node(l,j,2);}}else if(yuu[l].op==2){int b=yuu[l].b;{dp[l+1][t]=dp[l][j];pre[l+1][t]=node(l,j,0);}}else if(yuu[l].op==4){int a=yuu[l].a;if(dp[a][j]<dp[l][j]){dp[a][j]=dp[l][j];pre[a][j]=node(l,j,0);}}else{int a=yuu[l].a,b=yuu[l].b,c=yuu[l].c;if(j<a){if(dp[b][j]<dp[l][j]){dp[b][j]=dp[l][j];pre[b][j]=node(l,j,0);}}else{if(dp[c][j]<dp[l][j]){dp[c][j]=dp[l][j];pre[c][j]=node(l,j,0);}}}}int s=tp+1,t=endro[i]+1;Id[s]=i;for(int j=0;j<=1000;j++)if(dp[t][j]<dp[s][j]+ad){dp[t][j]=dp[s][j]+ad;pre[t][j]=node(s,j,3);}}//9.22925584//10.20218188int tj=0;for(int i=1;i<=1000;i++)if(dp[n+1][tj]<dp[n+1][i])tj=i;int ti=n+1,cnt=0;while(ti){int tx=ti,ty=tj;ti=pre[tx][ty].i,tj=pre[tx][ty].j;if(pre[tx][ty].cho){if(pre[tx][ty].cho==3){int id=Id[ti];for(int i=ct[id];i;i--) ans[++cnt]=as[id][i];}elseans[++cnt]=pre[tx][ty].cho;}}for(int i=cnt;i;i--) printf("%d\n",ans[i]);return 0;}2019.4.12Processing math: 0%。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Solution By Doveccl
什么是逆序对呢?
在一个数组 A 中,如果 i>j 且 Ai>Aj ,则称(Ai,Aj)是一个逆序对 比如数组 A={4,1,3,2},有(4,1) , (4,3) , (4,2) , (3,2) 4 个逆序对。 求逆序对可以用定义法,双重循环搜索,O(n2):
for(int i=1;i<n;i++) for(int j=i+1;i<=n;j++) if(a[i]>a[j]) ans++;
第 6 页共 26 页
NOIP 2013 senior
if(b[i]<=b[j]) a[k++]=b[i++]; else {
a[k++]=b[j++]; sum+=(m-i+1); sum%=mod; } } while(i<=m) a[k++]=b[i++]; while(j<=r) a[k++]=b[j++]; return sum; } inline LL merge_sort(int *a,int l,int r,int *b) { LL sum=0; if(l<r) { int m=(l+r)>>1; sum+=merge_sort(a,l,m,b); sum+=merge_sort(a,m+1,r,b); sum+=merge(a,l,m,r,b); sum%=mod; } return sum; } int main() { freopen("match.in","r",stdin); freopen("match.out","w",stdout); int n,i; LL sum; scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i]), aa[i]=i; for(i=1;i<=n;i++) scanf("%d",&b[i]), bb[i]=i; qs(a,aa,1,n); qs(b,bb,1,n); for(i=1;i<=n;i++) b[aa[i]]=bb[i]; sum=merge_sort(b,1,n,temp); printf("%I64d",sum); return 0; }
NOIP 2013 senior
4 13 4 2 17 2 4
Solution By Doveccl
2
【输入输出样例说明】 最小距离是 10,最少需要交换 2 次,比如:交换第 1 列的中间 2 根火柴的位置,再交
换第 2 列中后 2 根火柴的位置。 【数据范围】 对于 10%的数据, 1 ≤ n ≤ 10; 对于 30%的数据,1 ≤ n ≤ 100; 对于 60%的数据,1 ≤ n ≤ 1,000; 对于 100%的数据,1 ≤ n ≤ 100,000,0 ≤火柴高度≤ 231 − 1。
游戏规则如下:每一轮第 0 号位置上的小伙伴顺时针走到第 m 号位置,第 1 号位置小 伙伴走到第 m+1 号位置,……,依此类推,第 n − m 号位置上的小伙伴走到第 0 号位置, 第 n-m+1 号位置上的小伙伴走到第 1 号位置,……,第 n-1 号位置上的小伙伴顺时针走到第 m-1 号位置。 现在,一共进行了 10k 轮,请问 x 号小伙伴最后走到了第几号位置。 【输入】
则可保持 A 不动,单独移动 B 中元素(不影响最优解) 在 A 中 5 对应 B 下标 5,2—4,3—3 ,4—1 ,1—2 。 现在需要解决的是,如何使(5、4、3、1、2)操作最少次数成为有序状态。
第 5 页共 26 页
NOIP 2013 senior
这就需要用到逆序对,最少操作次数即是逆序对数。
第 2 页共 26 页
NOIP 2013 senior
【分析】
Solution By Doveccl
对于本题,不难推出,所求解即为 (m 10 k+x) mod n 然而对于 k≤109,显然暴力求解是不行的,有很大的超时风险
大概有两种做法: 1、求出循环节,然后用 k mod 循环节长度即可(长度必然不会超过 n)
circle.out 5
【数据说明】 对于 30%的数据,0 < ������ < 7; 对于 80%的数据,0 < ������ < 107; 对于 100%的数据,1 < ������ < 1,000,000,0 < ������ < ������ ,1 ≤ x ≤ n,0 < ������ < 109。

其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离 最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个 最小交换次数对 99,999,997 取模的结果。
2、使用快速幂算法,以下程序将使用快速幂求解
【代码】
#include <cstdio> typedef long long LL; int m,n,k,x; LL qmul(int p,int k) {
LL temp=p,s=1; while(k!=0) {
if(k%2==1) s=(s*(temp%n))%n; temp=(temp*temp)%n; k=k/2; } return s; } int main() { freopen("circle.in","r",stdin); freopen("circle.out","w",stdout); scanf("%d%d%d%d",&n,&m,&k,&x); printf("%I64d",(m*qmul(10,k)+x)%n); return 0; }
i 1
i 1
i 1
n
欲求距离最小值,即是求 AiBi 的最大值,这样推理过程就和去年的“国王游戏” i 1
证明过程基本一样了,即若a b,c d , 则有ac bd ad bc (a, b,c, d N*)
所以贪心得证。
然后就是分别排序两个数组,得到对应的关系。
例如 A:5 2 3 4 1 B:4 1 3 2 5
全国信息学奥林匹克联赛(NOIP2013)复赛
提高组 —解题报告
NOIP 2013 解题报告
BY DOVECL
Doveccl
第 0 页共 26 页
NOIP 2013 senior
中文题目名称 英文题目与子目录名
可执行文件名 输入文件名 输出文件名 每个测试点时限 测试点数目 每个测试点分值 附加样例文件 结果比较方式 题目类型 运行内存上限
#include <cstring> #include <cstdio> #include <algorithm> #define MaxN 100010 #define mod 99999997 using namespace std; typedef long long LL; int a[MaxN],b[MaxN],temp[MaxN],aa[MaxN],bb[MaxN]; inline void qs(int *x,int *y,int l,int r) {
输入文件名为 truck.in。 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路。
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城 市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。

全文比较(过滤行末空格及文末回车)
传统 128M
传统 128M
传统 128M
第 1 页共 26 页
NOIP 2013 senior
1.转圈游戏
Solution By Doveccl
(circle.cpp/c/pas) 【问题描述】 n 个小伙伴(编号从 0 到 n-1)围坐一圈玩游戏。按照顺时针方向给 n 个位 置编号,从 0 到 n-1。最初,第 0 号小伙伴在第 0 号位置,第 1 号小伙伴在第 1 号位 置,……,依此类推。
Solution By Doveccl
第 7 页共 26 页
NOIP 2013 senior
Solution By Doveccl
3.货车运输
【问题描述】
(truck.cpp/c/pas)
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有 重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限 重的情况下,最多能运多重的货物。 【输入】
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市 运输货物到 y 城市,注意:x 不等于 y。 【输出】
int i=l,j=r,m=x[(l+r)>>1]; while(i<=j) {
while(x[i]<m)i++; while(x[j]>m)j--; if(i<=j) {
相关文档
最新文档