Noip2008普及组

【NOIP2008PJ】前言:

这次考试考的不好,第2题严重失误爆0,本可以妥妥的300分,上一等线,却只拿了200分二等都难。

第一题:

题目描述
   
每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括9位数字、1位识别码和3位分隔符,其规定格式如“x-xxx-xxxxx-x”,其中符号“-”是分隔符(键盘上的减号),最后一位是识别码,例如0-670-82162-4就是一个标准的ISBN码。ISBN码的首位数字表示书籍的出版语言,例如0代表英语;第一个分隔符“-”之后的三位数字代表出版社,例如670代表维京出版社;第二个分隔之后的五位数字代表该书在出版社的编号;最后一位为识别码。
    识别码的计算方法如下:
    首位数字乘以1加上次位数字乘以2……以此类推,用所得的结果mod 11,所得的余数即为识别码,如果余数为10,则识别码为大写字母X。例如ISBN号码0-670-82162-4中的识别码4是这样得到的:对067082162这9个数字,从左至右,分别乘以1,2,…,9,再求和,即0×1+6×2+……+2×9=158,然后取158 mod 11的结果4作为识别码。
      你的任务是编写程序判断输入的ISBN号码中识别码是否正确,如果正确,则仅输出“Right”;如果错误,则输出你认为是正确的ISBN号码。 

输入

      输入文件isbn.in只有一行,是一个字符序列,表示一本书的ISBN号码(保证输入符合ISBN号码的格式要求)。

输出
       输出文件isbn.out共一行,假如输入的ISBN号码的识别码正确,那么输出“Right”,否则,按照规定的格式,输出正确的ISBN号码(包括分隔符“-”)。


样例输入
Sample Input1:
0-670-82162-4
Sample Input2:

0-670-82162-0


样例输出
Sample Output1:

Right
Sample  Output2:
0-670-82162-4


这道题就是简单的模拟,根据题目的描述模拟判断一下即可:

var
        a:array[0..13]of char;
        i,j,n,m,x:longint;
        c,r:char;
begin
		assign(input,'isbn.in'); reset(input);
		assign(output,'isbn.out'); rewrite(output);
		
        i:=1;
        m:=0;
        while j<13 do
        Begin
                inc(j);
                read(a[j]);
                if (a[j]<>'-')and(j<=11) Then
                Begin
                        m:=m+(ord(a[j])-48)*i;
                        inc(i);
                End;
        End;
        if m mod 11=10 Then r:='X' else r:=chr(ord('0')+(m mod 11));;
        if (a[13]=r) then
        begin
                writeln('Right')
        end
        else
        begin
                writeln(a[1],'-',a[3],a[4],a[5],'-',a[7],a[8],a[9],a[10],a[11],'-',r);
        end;
		
		close(input); close(output);
end.

第二题:

题目描述

上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情。不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的D对同学上课时会交头接耳。同学们在教室中坐成了M行N列,坐在第i行第j列的同学的位置是(i,j),为了方便同学们进出,在教室中设置了K条横向的通道,L条纵向的通道。于是,聪明的小雪想到了一个办法,或许可以减少上课时学生交头接耳的问题:她打算重新摆放桌椅,改变同学们桌椅间通道的位置,因为如果一条通道隔开了两个会交头接耳的同学,那么他们就不会交头接耳了。
请你帮忙给小雪编写一个程序,给出最好的通道划分方案。在该方案下,上课时交头接耳的学生的对数最少。
输入输出格式
输入格式:
输入文件seat.in的第一行,有5个用空格隔开的整数,分别是M,N,K,L,D(2<=N,M<=1000,0<=K<M,0<=L<N,D<=2000)。
接下来的D行,每行有4个用空格隔开的整数。第i行的4个整数Xi,Yi,Pi,Qi,表示坐在位置(Xi,Yi)与(Pi,Qi)的两个同学会交头接耳(输入保证他们前后相邻或者左右相邻)。

输入数据保证最优方案的唯一性。
输出格式:
输出文件seat.out共两行。
第一行包含K个整数,a1,a2……aK,表示第a1行和a1+1行之间、第a2行和a2+1行之间、…、第aK行和第aK+1行之间要开辟通道,其中ai< ai+1,每两个整数之间用空格隔开(行尾没有空格)。
第二行包含L个整数,b1,b2……bL,表示第b1列和b1+1列之间、第b2列和b2+1列之间、…、第bL列和第bL+1列之间要开辟通道,其中bi< bi+1,每两个整数之间用空格隔开(列尾没有空格)。

输入输出样例
输入样例#1:
4 5 1 2 3
4 2 4 3
2 3 3 3
2 5 2 4
输出样例#1:
2
2 4

【输入输出样例解释】

上图中用符号*、※、+ 标出了3对会交头接耳的学生的位置,图中3条粗线的位置表示通道,图示的通道划分方案是唯一的最佳方案。


这道题目需要讲一下爆0的原因,首先,我们肯定是根据贪心的算法把每一列最多的交头接耳的人和每一行最多的交头接耳的人都删掉,然后最后再按num[i]从小到大输出——而我爆0的原因是因为我没想到输入的两个人不一定一定是连在一起的,如果他们不相邻,则没必要理会了,所以就需在输入的时候加特殊判断。

代码:

type
         re=record
                tot,num:longint;
        end;
        arr=array[1..2000] of re;
var
        n,m,k,w,D,x1,y1,x2,y2,lena,lenb,i,j:longint;
        bz:array[0..1000,0..1000] of longint;
        a,b:arr;
        p:re;
procedure sort(l,r:longint;var a:arr);
var
        i,j,mid,mie:longint;
begin
        i:=l; j:=r;
        mid:=a[(l+r) div 2].tot;
        mie:=a[(l+r) div 2].num;
        while i<j do
        begin
                while (a[i].tot>mid) do inc(i);
                while (a[j].tot<mid) do dec(j);
                if i<=j then
                begin
                        p:=a[i]; a[i]:=a[j]; a[j]:=p;
                        inc(i); dec(j);
                end;
        end;
        if l<j then sort(l,j,a);
        if i<r then sort(i,r,a);
end;
procedure qsort(l,r:longint;var a:arr);
var
        i,j,mid:longint;
begin
        i:=l; j:=r;
        mid:=a[(l+r) div 2].num;
        while i<j do
        begin
                while a[i].num<mid do inc(i);
                while a[j].num>mid do dec(j);
                if i<=j then
                begin
                        p:=a[i]; a[i]:=a[j]; a[j]:=p;
                        inc(i); dec(j);
                end;
        end;
        if l<j then qsort(l,j,a);
        if i<r then qsort(i,r,a);
end;

begin
        assign(input,'seat.in'); reset(input);
        assign(output,'seat.out'); rewrite(output);

        readln(m,n,k,w,d);
        for i:=1 to d do
        begin
                readln(x1,y1,x2,y2);
                if (y1=y2) and (x1<>x2) then
                begin
                        if x1>x2 then x1:=x2;
                        inc(a[x1].tot);
                        a[x1].num:=x1;
                end;
                if (x1=x2) and (y1<>y2) then
                begin
                        if y1>y2 then y1:=y2;
                        inc(b[y1].tot);
                        b[y1].num:=y1;
                end;
        end;
        sort(1,m,a);
        sort(1,n,b);
        qsort(1,k,a);
        qsort(1,w,b);
        for i:=1 to k-1 do
                write(a[i].num,' ');
        writeln(a[k].num);
        for i:=1 to w-1 do
                write(b[i].num,' ');
        writeln(b[w].num);

        close(input); close(output);
end.

第三题:

题目描述
上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。
游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师在此吹哨子时,传球停止,此时,拿着球没有传出去的那个同学就是败者,要给大家表演一个节目。
聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m次以后,又回到小蛮手里。两种传球方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有三个同学1号、2号、3号,并假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共2种。

输入输出格式
输入格式:

输入文件ball.in共一行,有两个用空格隔开的整数n,m(3<=n<=30,1<=m<=30)。

输出格式:
输出文件ball.out共一行,有一个整数,表示符合题意的方法数。

输入输出样例
输入样例#1:
3 3
输出样例#1:
2


这道题目考试的时候因为没想到DP,就用了dfs+打表偷了100分,实际上这道题的DP也很简单,只需设f[i,j]表示第j个人传i次的方案数,然后f[i,j]只有可能从其左右得来,所以加上其左右的方案数就可以了。

代码:

var
        f:array[0..30,1..30] of longint;
        I,J,K,N,M:longint;
begin
        readln(n,m);
        f[0,1]:=1;
        for i:=1 to m do
                for j:=1 to n do
                begin
                        k:=j+1;
                        if k>n then k:=1;
                        f[i,j]:=f[i,j]+f[i-1,k];
                        k:=j-1;
                        if k<1 then k:=n;
                        f[i,j]:=f[i,j]+f[i-1,k];
                end;
        writeln(f[m,1]);
end.


第四题:

小渊是个聪明的孩子,他经常会给周围的小朋友们将写自己认为有趣的内容。最近,他准备给小朋友们讲解立体图,请你帮他画出立体图。小渊有一块面积为m*n的矩形区域,上面有m*n个边长为1的格子,每个格子上堆了一些同样大小的积木(积木的长宽高都是1),小渊想请你打印出这些格子的立体图。我们定义每个积木为如下格式,并且不会做任何翻转旋转,只会严格以这一种形式摆放:每个顶点用1个加号’+’表示,长用3个”-”表示,宽用1个”/”,高用两个”|”表示。字符’+’,”-”,”/”,”|”的ASCII码分别为43,45,47,124。字符’.’(ASCII码46)需要作为背景输出,即立体图里的空白部分需要用’.’来代替。立体图的画法如下面的规则:若两块积木左右相邻,图示为:若两块积木上下相邻,图示为:若两块积木前后相邻,图示为:立体图中,定义位于第(m,1)的格子(即第m行第1列的格子)上面自底向上的第一块积木(即最下面的一块积木)的左下角顶点为整张图最左下角的点。

输入输出格式

输入格式:输入文件drawing.in第一行有用空格隔开的2个整数m和n,表示有m*n个格子(1<=m,n<=50)。接下来的m行,是一个m*n的矩阵,每行有n个用空格隔开的整数,其中第i行第j列上的整数表示第i行第j列的个子上摞有多少个积木(1<=每个格子上的积木数<=100)。输出格式:

输出文件drawing.out中包含题目要求的立体图,是一个K行L列的字符串矩阵,其中K和L表示最少需要K行L列才能按规定输出立体图。


输入输出样例


输入样例#1:
3 4
2 2 1 2
2 2 1 1
3 2 1 2
输出样例#1:

......+---+---+...+---+
..+---+  /   /|../   /|
./   /|-+---+ |.+---+ |
+---+ |/   /| +-|   | +
|   | +---+ |/+---+ |/|
|   |/   /| +/   /|-+ |
+---+---+ |/+---+ |/| +
|   |   | +-|   | + |/.
|   |   |/  |   |-| +..
+---+---+---+---+ |/...
|   |   |   |   | +....
|   |   |   |   |/.....
+---+---+---+---+......

这道题目其实就是在一个二维数组里绘图,而每次绘图的时候需要把坐标更新,例如,一行画完了要更新y,一列画完了要更新j,一列当中的一个图绘完了也要更新,这样子做了之后最后再在数组里找出边界——输出。

const
        ch:Array[1..6] of string=(('..+---+'),
                                  ('./   /|'),
                                  ('+---+ |'),
                                  ('|   | +'),
                                  ('|   |/.'),
                                  ('+---+..'));
var
        x,y:longint;
        i,j,k,m,n,max,len,min1,min2,max1,max2:longint;
        a:array[1..50,1..50] of longint;
        bz:array[0..400,0..300] of char;
procedure draw(x1,y1,t:longint);
var
        i,j:longint;
begin
        for i:=x1 to x1+5 do
                for j:=y1 to y1+6 do
                        if (ch[i-x1+1,j-y1+1]<>'.') then bz[i,j]:=ch[i-x1+1,j-y1+1];
end;

begin
		assign(input,'drawing.in'); reset(input);
		assign(output,'drawing.out'); rewrite(output);

        readln(m,n);
        for i:=1 to m do
                for j:=1 to n do
                        read(a[i,j]);
        for i:=1 to m do
        begin
                y:=99;
                dec(y,(i-1)*2);
                for j:=1 to n do
                begin
                        x:=300;
                        inc(x,(i-1)*2);
                        for k:=1 to a[i,j] do
                        begin
                                draw(x,y,k);
                                x:=x-3;
                        end;
                        y:=y+4;
                end;
        end;

        min1:=maxlongint;
        max1:=maxlongint;
        for i:=0 to 400 do
                for j:=0 to 300 do
                        if (bz[i,j] in ['+','-','/','|'])then
                        begin
                                if i<min1 then min1:=i;
                                if i>min2 then min2:=i;
                                if j<max1 then max1:=j;
                                if j>max2 then max2:=j;
                        end;
        for i:=min1 to min2 do
        begin
                for j:=max1 to max2 do
                        if bz[i,j]=#0 then write('.') else write(bz[i,j]);
                writeln;
        end;
		
		close(input); close(output);
end.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值