NOIP2011 普及组复赛1 .数字反转(reverse.cpp/c/pas )【问题描述】给定一个整数,请将该数各个位上数字反转得到一个新数。
新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零。
(参见样例2)【输入】输入文件名为reverse. in 。
输入共一行,一个整数No【输出】输出文件名为reverse.out 。
输出共1行,一个整数,表示反转后的新数。
【输入输出样例1】-1,000,000,000 < N< 1,000,000,000 。
【解题】这道题非常简单,可以读字符串处理,也可以读数字来处理,只不过要注意符号问题(以及但测试数据没出)。
-0 , 【法一】字符串处理Var i,l,k:i nteger;s:stri ng;p:boolea n;beginassig n(i nput, 'reverse.i n'); reset(i nput);assig n(o utput, 'reverse.out'); rewrite(output);readl n( s);l:=le ngth(s);k:=1;if s[1]=' -' the nbeginwrite('-');k:=2;en d;p:=true;;for i:=l dow nto k dobeginif(p)a nd((s[i]='0')) the n continueelsebeginwrite(s[i]); p:=false;;en d;en d;close(i nput); close(output);en d.【法二】数字处理Var f:i nteger;n,an s:lo ngint;beginassig n(i nput, 'reverse.i n'); reset(i nput);assig n(o utput, 'reverse.out'); rewrite(output);readl n(n);if n<0 the nbegin f:=-1; n :=-n;endelsef:=1;an s:=0;while n<>0 dobeginan s:=a ns*10+n mod 10; n:=n div 10;en d;an s:=a ns*f;writel n(a ns);close(i nput); close(output);en d.2.统计单词数(stat.pas/c/cpp)【问题描述】一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数。
现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给定的文章中出现的次数和第一次出现的位置。
注意:匹配单词时,不区分大小写,但要求完全匹配,即给定单词必须与文章中的某一独立单词在不区分大小写的情况下完全相同(参见样例1),如果给定单词仅是文章中某一单词的一部分则不算匹配(参见样例2)【输入】输入文件名为stat.in, 2行。
第1行为一个字符串,其中只含字母,表示给定单词;第2行为一个字符串,其中只可能包含字母和空格,表示给定的文章。
【输出】输出文件名为stat.out。
只有一行,如果在文章中找到给定单词则输出两个整数,两个整数之间用一个空格隔开,分别是单词在文章中出现的次数和第一次出现的位置(即在文章中第一次出现时,单词首字母在文章中的位置,位置从0开始);如果单词在文章中没有出现,则直接输出一个整数-1。
【输入输出样例1】1输出结果表示给定的单词To在文章中出现两次,第一次出现的位置为0。
2表示给定的单词to在文章中没有出现,输出整数-1。
【数据范围】1W单词长度w 10。
1W文章长度w 1,000,000。
【解题】这道题也不是很难,program stat; var l,n, p:l ongint;s,s1:stri ng; c:char;beginassig n(i nput,'stat.i n'); reset(i nput);assig n(o utput,'stat.out'); rewrite(output);readl n( s);s:=upcase(s); // 函数upcase() 参数可为char,也可为stringi:=-1; //i统计读入的字符位置,首个字符出现的位置是0s1:=”;〃s1累加读入的字符n:=0; 〃n统计出现次数p:=-1; 〃p标记第一次出现的位置repeatread(c);c:=upcase(c); // 统一大小写i:=i+1;if c=' ' the n //遇到空格,匹配是否相同beginif s=s1 the nbeginn:=n+1;if p=-1 then 〃p标记第一次出现的位置,如果p是第一次更改,记录位置p:=i-le ngth(s);en d;s1:=";endelses1:=s1+c; //不是空格,继续叠加un til eoln (i nput);if s1=s then //处理最后一个单词是否相同的情况beginn:=n+1;if p=-1 the np:=i-le ngth(s) +1; // 最后没有空格en d;if n=0 then writel n(-1)else writel n(n,' ',p);close(i nput);close(output);en d.3.瑞士轮(swiss.cpp/c/pas)【背景】在双人对决的竞技性比赛,如乒乓球、羽毛球、国际象棋中,最常见的赛制是淘汰赛和循环赛。
前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高。
后者的特点是较为公平,偶然性较低,但比赛过程往往十分冗长。
本题中介绍的瑞士轮赛制,因最早使用于1895年在瑞士举办的国际象棋比赛而得名。
它可以看作是淘汰赛与循环赛的折衷,既保证了比赛的稳定性,又能使赛程不至于过长。
【问题描述】2*N名编号为1~2N的选手共进行R轮比赛。
每轮比赛开始前,以及所有比赛结束后,都会按照总分从高到低对选手进行一次排名。
选手的总分为第一轮开始前的初始分数加上已参加过的所有比赛的得分和。
总分相同的,约定编号较小的选手排名靠前。
每轮比赛的对阵安排与该轮比赛开始前的排名有关:第1名和第2名、第3名和第4名、……、第2K - 1名和第2K名、……、第2N - 1名和第2N名,各进行一场比赛。
每场比赛胜者得1分,负者得0分。
也就是说除了首轮以外,其它轮比赛的安排均不能事先确定,而是要取决于选手在之前比赛中的表现。
现给定每个选手的初始分数及其实力值,试计算在R轮比赛过后,排名第Q的选手编号是多少。
我们假设选手的实力值两两不同,且每场比赛中实力值较高的总能获胜。
【输入】输入文件名为swiss.in 。
输入的第一行是三个正整数N、R、Q,每两个数之间用一个空格隔开,表示有2*N名选手、R轮比赛,以及我们关心的名次Q。
第二行是2*N个非负整数S1, S2,…,S N,每两个数之间用一个空格隔开,其中s表示编号为i的选手的初始分数。
第三行是2*N个正整数W1, W2,…,WN,每两个数之间用一个空格隔开,其中wi表示编号为i的选手的实力值。
【输出】输出文件名为swiss.out 。
输出只有一行,包含一个整数,即R轮比赛结束后,排名第Q的选手的编号。
【输入输出样例】【输入输出样例说明】【数据范围】对于30%的数据,1 < N < 100;对于50%的数据,1 < N< 10,000;对于100%的数据,1 < N < 100,000, K R< 50, K Q< 2N, 0< S1, S2,…,S N w 108, K w1,W2,…,ww 108。
【解题】题目虽然长,但理解题意后就发现解题的瓶颈在于排序。
如果每一轮比赛的结果都进行快速排序,时间复杂度为0 (Rlongn ),但事实证明这样只能拿60分。
如何AC,这需要一个巧算法:分析得知,快速排序实际上进行了许多无用的工作:如果两个人在第i轮都赢了,那么第i轮后的先后关系与第i-1轮是一样的;反之,如果两人都输了,他们的先后关系也不会变。
所以,我们有一个新算法:一开始做一趟快速排序,然后对于每一轮,将此轮的n个赢者(他们的先后关系和上一轮不变)和n个输者(他们的先后关系和上一轮也不变分开,然后就是归并,于是时间复杂度0 (Rn)) (实践证明,如果单纯的排序r次,必然结果是超时。
事实上只需一次真正意义上的排序以后,在以后的比赛中,按原顺序分成两组,获胜组和失败组,这两组依然是有序的,再把这两组归并成一组,就可以了。
总时间复杂度O(N*R)program swiss;var a,b,v:array[1..200000]of Ion gi nt;c,d:array[1..100000,1..2]of Ion gi nt;n ,r,q,i,j:l on gi nt;procedure qsort(l,r:l ongin t); var i,j,mid1,mid2,t:lo ngint; begini:=l;j:=r; mid1:=a[(l+r)div 2]; mid2:=v[(l+r)div 2];repeat 〃按分数从高到低排序,分数相同的,编号较小的选手排名靠前while (a[i]>mid1) or (a[i]=mid1) and (v[i]<mid2) do in c(i);while (a[j]<mid1) or (a[j]=mid1) and (v[j]>mid2) do dec(j);if i<=j the nbegint:=a[i]; a[i]:=a[j]; a[j]:=t;t:=v[i]; v[i]:=v[j]; v[j]:=t;in c(i); dec(j);en d;un til i>j;if i<r the n qsort(i,r);if l<j then qsort(l,j);en d;procedure mergesort; // 归并排序var i,l1,l2:lo ngi nt; begini:=0; l1:=1; l2:=1; repeatif (c[l1,1]>d[l2,1])or (c[l1,1]=d[l2,1])a nd(c[l1,2]<d[l2,2]) then begini:=i+1;a[i]:=c[l1,1]; v[i]:=c[l1,2]; 11:=11+1; end elsebegini:=i+1;a[i]:=d[l2,1]; v[i]:=d[l2,2]; 12:=12+1; en d;un til (l1> n)or(l2> n); while l1<=n dobegini:=i+1;a[i]:=c[l1,1]; v[i]:=c[l1,2]; 11:=11+1; en d; while l2<=n dobegini:=i+1;a[i]:=d[l2,1]; v[i]:=d[l2,2]; 12:=12+1; en d; en d;begin//王程序assig n(i nput,'swiss.i n');reset(i nput); assig n(o utput,'swiss.out');rewrite(output);c[j,1]:=a[2*j]; c[j,2]:=v[2*j]; d[j,1]:=a[2*j-1];readl n(n ,r,q);for i:= 1 to n*2 do read(a[i]); for i:= 1 to n*2 do read(b[i]); for i:=1 to n*2 do v[i]:=i; qsort(1,2* n); for i:= 1 to r dobeginfor j:= 1 to n doif b[v[2*j-1]]>b[v[2*j]] thenbeginin c(a[2*j-1]); c[j,1]:=a[2*j-1]; c[j,2]:=v[2*j-1]; d[j,1]:=a[2*j]; d[j,2]:=v[2*j]; endelsebeginin c(a[2*j]);//数组a 保存初始分数〃数组b 保存实力值〃数组v[i]保存排名第i 的选手编号〃数组c[j,1]保存嬴方的总分;数组 〃数组d[j,1]保存输方的总分;数组c[j,2]保存嬴方的号码;d[j,2]保存输方的号码;d[j,2]:=v[2*j-1]; en d;mergesort;en d;writel n(v[q]);close(i nput);close(output); en d.4.表达式的值(exp.cpp/c/pas)【问题描述】1运算的优先级是:1.先计算括号内的,再计算括号外的。