切换到宽版
  • 9228阅读
  • 4回复

NOIP2005提高组解题报告 [复制链接]

上一主题 下一主题
离线little影
 
只看楼主 倒序阅读 0 发表于: 2005-12-22
谁拿了最多奖学金(scholar)



题目概述:



已知每个学生的个人信息,求出获得奖学金最多的学生姓名、金额,以及全部奖学金金额。

算法分析:



模拟



其中涉及简单的字符处理,特别要注意数据类型的应用。如:学生姓名可采用char和string相结合的方法处理,奖学金金额用longint较为适宜。



程序:



  1. program scholar;
  2. var name:array[1..100] of string;
  3.   a1,a2,a5:array[1..100] of longint;
  4.   a3,a4:array[1..100] of char;
  5.   n,i,max,total,p:longint;
  6.   maxname:string;
  7.   ch:char;
  8.   f:text;
  9. begin
  10.   assign(f,'scholar.in');reset(f);
  11.   readln(f,n);
  12.   for i:=1 to n do
  13.   begin
  14.       read(f,ch);
  15.       while ch<>' ' do
  16.       begin
  17.         name[i]:=name[i]+ch;
  18.           read(f,ch);
  19.       end;
  20.       readln(f,a1[i],a2[i],ch,a3[i],ch,a4[i],ch,a5[i]);
  21.   end;
  22.   close(f);
  23.   for i:=1 to n do
  24.   begin
  25.       p:=0;
  26.       if (a1[i]>80) and (a5[i]>=1) then inc(p,8000);
  27.       if (a1[i]>85) and (a2[i]>80) then inc(p,4000);
  28.       if (a1[i]>90) then inc(p,2000);
  29.       if (a1[i]>85) and (a4[i]='Y') then inc(p,1000);
  30.       if (a2[i]>80) and (a3[i]='Y') then inc(p,850);
  31.       if p>max then
  32.       begin
  33.           max:=p;
  34.           maxname:=name[i];
  35.       end;
  36.       inc(total,p);
  37.   end;
  38.   assign(f,'scholar.out');rewrite(f);
  39.   writeln(f,maxname);
  40.   writeln(f,max);
  41.   writeln(f,total);
  42.   close(f);
  43. end.




过河(River)



题目概述:



在一条长为L数轴上有若干障碍点,每次前进距离为S到T之间的任意正整数(包括S,T),求走过L或大于L的距离,遇到最少的障碍点。



算法分析:



看到题目首先想到的是时间复杂度为O(L)的递推算法。但是L的上限为10^9,这种算法显然是不行的。仔细思考,可以得到下面的结论:



存在N0,当n> N0时,n可以由若干S到T之间的正整数(包括S,T)组成。



因此,将障碍点按升序排列,当两相邻障碍点之间距离较大时,可适当缩小两障碍点之间距离,但不影响最终结果。



根据上述结论,改进递推算法。由于障碍点之间距离大大缩减,算法的复杂度是可以承受的。



特别地,当S=T时需要单独处理。



程序:



  1. program river;
  2. const max=105;
  3. var a,a1:array[0..101] of longint;
  4.   b:array[0..100] of boolean;
  5.   c,d:array[0..10000] of longint;
  6.   l,s,t,m,ans,low,i,j,k,temp:longint;
  7.   flag:boolean;
  8.   f:text;
  9. procedure init;
  10. begin
  11.   assign(f,'river9.in');reset(f);
  12.   readln(f,l);
  13.   readln(f,s,t,m);
  14.   for i:=1 to m do read(f,a[i]);
  15.   a[0]:=0;a[m+1]:=l;
  16.   for i:=1 to m-1 do
  17.   for j:=i+1 to m do
  18.   if a[i]>a[j] then
  19.   begin
  20.       temp:=a[i];a[i]:=a[j];a[j]:=temp;
  21.   end;
  22.   close(f);
  23. end;
  24. procedure work1;
  25. begin
  26.   for i:=1 to m do
  27.   if a[i] mod s=0 then inc(ans);
  28. end;
  29. procedure work2;
  30. begin
  31.   fillchar(b,sizeof(b),false);
  32.   b[0]:=true;
  33.   for i:=s to t do
  34.   begin
  35.       for j:=0 to 100 do
  36.       if b[j] then
  37.       begin
  38.           k:=1;
  39.           while k*i+j<=100 do
  40.           begin
  41.             b[k*i+j]:=true;
  42.             inc(k);
  43.           end;
  44.       end;
  45.   end;
  46.   for i:=1 to 100 do
  47.   begin
  48.       flag:=true;
  49.       for j:=0 to t-1 do
  50.       if not b[i+j] then begin flag:=false;break;end;
  51.       if flag then
  52.       begin
  53.         low:=i;
  54.           break;
  55.       end;
  56.   end;
  57.   if low<t then low:=t;
  58.   for i:=1 to m+1 do
  59.   begin
  60.       a1[i]:=(a[i]-a[i-1]-low) mod low+a1[i-1]+low;
  61.   end;
  62.   a:=a1;
  63.   for i:=1 to m do d[a[i]]:=1;
  64.   l:=a[m+1];
  65.   for i:=1 to l+t-1 do c[i]:=max;
  66.   for i:=1 to l+t-1 do
  67.   for j:=s to t do
  68.   if (i-j>=0) and (c[i]>c[i-j]+d[i]) then
  69.     c[i]:=c[i-j]+d[i];
  70.   ans:=max;
  71.   for i:=l to l+t-1 do
  72.   if ans>c[i] then ans:=c[i];
  73. end;
  74. begin
  75.   init;
  76.   if s=t then work1
  77.   else work2;
  78.   assign(f,'river.out');rewrite(f);
  79.   writeln(f,ans);
  80.   close(f);
  81. end.







篝火晚会(fire)



题目概述:



  根据一定的移动规则,将初始圆环转化为满足一定条件的目标圆环。

算法分析:



从第一个人处断开,将圆环的问题转化为序列的问题。如果可以,求出目标序列。求出目标序列复杂度O(n).



求出目标序列右移0至n-1位置时,不需要移动的人数。将目标序列反转,再求出目标序列右移0至n-1位置时,不需要移动的人数。不需要移动的人数最大等价于需要移动的人数最小。复杂度O(n)。

程序:
  1. program fire;
  2. var a:array[1..50000] of longint;
  3.   b:array[1..50000,1..2] of longint;
  4.   d:array[1..50000] of longint;
  5.   w:array[0..50000] of longint;
  6.   n,ans,i,j,t,max:longint;
  7.   flag:boolean;
  8.   f:text;
  9. procedure init;
  10. begin
  11.   assign(f,'fire.in');reset(f);
  12.   readln(f,n);
  13.   for i:=1 to n do
  14.   begin
  15.       readln(f,b[i,1],b[i,2]);
  16.       inc(d[b[i,1]]);
  17.       inc(d[b[i,2]]);
  18.   end;
  19.   close(f);
  20.   for i:=1 to n do
  21.   if d[i]<>2 then begin flag:=false;exit;end;
  22. end;
  23. procedure circle;
  24. begin
  25.   a[1]:=1;a[2]:=b[1,1];
  26.   for i:=3 to n do
  27.   if b[a[i-1],1]<>a[i-2] then a[i]:=b[a[i-1],1]
  28.   else a[i]:=b[a[i-1],2];
  29.   if a[n]<>b[1,2] then flag:=false;
  30. end;
  31. procedure min;
  32. begin
  33.   fillchar(w,sizeof(w),0);
  34.   for i:=1 to n do
  35.       inc(w[(a[i]-i+n) mod n]);
  36.   for i:=0 to n-1 do
  37.   if max<w[i] then max:=w[i];
  38.   for i:=1 to (n+1) div 2 do
  39.   begin
  40.       t:=a[i];a[i]:=a[n+1-i];a[n+1-i]:=t;
  41.   end;
  42.   fillchar(w,sizeof(w),0);
  43.   for i:=1 to n do
  44.       inc(w[(a[i]-i+n) mod n]);
  45.   for i:=0 to n-1 do
  46.   if max<w[i] then max:=w[i];
  47.   ans:=n-max;
  48. end;
  49. begin
  50.   flag:=true;
  51.   init;
  52.   if flag then circle;
  53.   if flag then min;
  54.   assign(f,'fire.out');rewrite(f);
  55.   if flag then writeln(f,ans) else writeln(f,-1);
  56.   close(f);
  57. end.

 



等价表达式



题目概述:



判断两表达式是否等价。

算法分析:



用栈的方法求表达式的值是经典的算法。考虑到多项式的处理比较麻烦,不妨对变量a进行多次赋值以判断表达式是否等价。



  值得注意,由于进行数值运算,采用哪种数据类型成为程序是否正确的关键。下面的程序,采取mod m的方法,其中m为任意正整数。当对a多次赋值,且m取不同的较大的正整数时,可以保证算法的正确性。



程序:



  1. program equal;
  2. const max=maxlongint;
  3. const com:array[1..7,1..7] of char=(('>','>','<','<','<','>','>'),
  4.                       ('>','>','<','<','<','>','>'),
  5.                       ('>','>','>','<','<','>','>'),
  6.                       ('>','>','>','>','<','>','>'),
  7.                       ('<','<','<','<','<','=','X'),
  8.                       ('>','>','>','>','X','>','>'),
  9.                       ('<','<','<','<','<','X','X'));
  10. var there:char;
  11.   oped:array[1..1000] of longint;
  12.   optr:array[1..1000] of char;
  13.   ned,ntr:int64;
  14.   a,b:int64;
  15.   flag:boolean;
  16.   s:array[0..26] of string;
  17.   value:array[0..26,-4..4] of int64;
  18.   ans:array[0..26] of boolean;
  19.   n,i,j,p,q:longint;
  20.   f:text;
  21. function compare(w1,w2:char):char;
  22. var x1,x2:integer;
  23. begin
  24.   case w1 of
  25.       '+':x1:=1;
  26.       '-':x1:=2;
  27.       '*':x1:=3;
  28.       '^':x1:=4;
  29.       '(':x1:=5;
  30.       ')':x1:=6;
  31.       '#':x1:=7;
  32.   end;
  33.   case w2 of
  34.       '+':x2:=1;
  35.       '-':x2:=2;
  36.       '*':x2:=3;
  37.       '^':x2:=4;
  38.       '(':x2:=5;
  39.       ')':x2:=6;
  40.       '#':x2:=7;
  41.   end;
  42.   compare:=com[x1,x2];
  43. end;
  44. function operation(a:int64;there:char;b:int64):int64;
  45. var i:longint;
  46. begin
  47.   case there of
  48.       '+':operation:=(a+b) mod max;
  49.       '-':operation:=(a-b) mod max;
  50.       '*':operation:=(a*b) mod max;
  51.       '^':begin operation:=1;for i:=1 to b do
  52. operation:=operation*a mod max;end;
  53.   end;
  54. end;
  55. function exp(s:string;aa:int64):int64;
  56. var i:int64;
  57. begin
  58.   s:=s+'#';
  59.   i:=1;
  60.   ned:=0;ntr:=1;
  61.   fillchar(oped,sizeof(oped),0);
  62.   optr:='';
  63.   optr[1]:='#';flag:=false;
  64.   while not ((s[i]='#')and (optr[ntr]='#')) do
  65.   begin
  66.       if s[i] in ['0'..'9'] then
  67.       begin
  68.           if not flag then
  69.           begin
  70.             ned:=ned+1;
  71.             oped[ned]:=ord(s[i])-ord('0');
  72.             flag:=true;
  73.             inc(i);
  74.           end
  75.           else
  76.           begin
  77.             oped[ned]:=oped[ned]*10+ord(s[i])-ord('0');
  78.             inc(i);
  79.           end;
  80.       end
  81.       else
  82.       if s[i]='a' then
  83.       begin
  84.           inc(ned);
  85.           oped[ned]:=aa;
  86.           inc(i);
  87.       end
  88.       else if s[i]=' ' then inc(i)
  89.       else
  90.       begin
  91.           flag:=false;
  92.           case compare(optr[ntr],s[i]) of
  93.             '<':begin ntr:=ntr+1;optr[ntr]:=s[i];inc(i);end;
  94.             '>':begin
  95.                   there:=optr[ntr];ntr:=ntr-1;
  96.                   b:=oped[ned];ned:=ned-1;
  97.                   a:=oped[ned];
  98.                   oped[ned]:=operation(a,there,b);
  99.                 end;
  100.             '=':begin ntr:=ntr-1;inc(i);end;
  101.           end;
  102.       end;
  103.   end;
  104.   exp:=oped[1];
  105. end;
  106. begin
  107.   assign(f,'equal.in');reset(f);
  108.   readln(f,s[0]);
  109.   readln(f,n);
  110.   for i:=1 to n do readln(f,s[i]);
  111.   fillchar(ans,sizeof(ans),true);
  112.   close(f);
  113.   for i:=0 to n do
  114.   if ans[i] then
  115.   for j:=-4 to 4 do
  116.   begin
  117.       value[i,j]:=exp(s[i],j);
  118.       if value[i,j]<>value[0,j] then begin ans[i]:=false;break;end;
  119.   end;
  120.   assign(f,'equal.out');rewrite(f);
  121.   for i:=1 to n do
  122.       if ans[i] then write(f,chr(ord('A')+i-1));
  123.   writeln(f);
  124.   close(f);
  125. end.
[ 此贴被sammy312在2006-08-16 20:14重新编辑 ]
只看该作者 1 发表于: 2006-04-29
看不懂啊!!!!!!!!!!!!!!
只看该作者 2 发表于: 2006-04-29
能讲一下思路吗??????????????????????????????
离线stevenjl

只看该作者 3 发表于: 2006-04-30
哪个题目不懂啊
Dream Walker...
只看该作者 4 发表于: 2006-05-11
2、3题,尤其是第3题。
快速回复
限100 字节
 
上一个 下一个