Thứ Hai, 7 tháng 12, 2015

lời giải 100 bài (phần cuối)

Bài 76/2001 - Đoạn thẳng và hình chữ nhật
(Dành cho học sinh PTTH)
Thuật toán:
- Xét đoạn thẳng cắt với từng cạnh của hình chữ nhật, điều kiện cắt của đoạn thẳng với một đoạn thẳng khác (cạnh của hình chữ nhật) là:
 + Hai đầu của đoạn thẳng khác phía với đoạn thẳng của hình chữ nhật;
 + Hai đầu của đoạn thẳng hình chữ nhật khác phía với đoạn thẳng.
Chương trình:
Program Bai76;
const inp= ‘input.txt’;
      out= ‘output.txt’;
function cat (xs, ys, xe, ye, xl, yt, xr, yb: real): boolean;
var a, b, x, y: real;
    lg1, lg2: boolean;
Begin
if xs=xe then
begin
  lg1:=(xs<xl) or (xs>xr) or ((ys>yt) and (ye>yt)) or ((ys<yb) and (ye<yb));
  lg2:=(xs>xl) and (xs<xr) and (ys<yt)and (ye<yt) and (ys>yb) and (ye>yb);
cat:=not (lg1 or lg2);
end
else begin
if ys=ye then
begin
  lg1:=((xs<xl) and (xe<xl)) or ((xs>xr) and (xe>xr)) or (ys>yt) or (ys<yb));
  lg2:=(xs>xl) and (xe>xl) and (xs<xr)and (xe<xr) and (ys<yt) and (ys>yb);
cat:=not (lg1 or lg2);
end
else begin
cat:=false;
a:=(ys-ye)/(xs-xe);
b:=ys-a*xs;
y:= a*xl+b;
if(y<=yt)and(y>=yb)then cat:= true;
y: =a*xr+b;
if(y<=yt)and(y>=yb)then cat:=true;
x:=(yt-b)/a;
if (x>=xl)and (x<=xr)then cat:=true;
x:=(yb-b)/a;
if (x>=xl)and (x<=xr)then cat:=true;
end;
end;
end;
procedure xuly;
var n, i: word; xs, ys, xe, ye, xl, yt, xr, yb: real;
fi, fo: text;
Begin
assign(fi, inp); reset (fi);
 assign (fo, out); rewrite(fo);
 readln(fi, n);
 for i:=1 to n do begin
  readln (fi, xs, ys, xe, ye, xl, yt, xr, yb);
  if cat (xs, ys, xe, ye, xl, yt, xr, yb) then writeln (fo, ‘T’)
   else writeln(fo, ‘F’);
 end;
close (fi);
close (fo);
end;
BEGIN
  xuly;
END.
(Lời giải của bạn Lê Mạnh Hà - Lớp 10A Tin - Khối PTCTT - ĐHKHTN - ĐHQG Hà Nội)

Bài 77/2001 - Xoá số trên bảng
(Dành cho học sinh Tiểu học)
1. Có thể thực hiện được.
Sau đây là một cách làm cụ thể: ta lần lượt xoá từng nhóm hai số một từ cuối lên: (23 - 22); (21 - 20); ....; (5 - 4); (3 - 2). Như vậy, sau 11 bước này trên bảng sẽ còn lại 12 số 1. Do đó, ta chỉ việc nhóm 12 số 1 này thành 6 nhóm có hiệu bằng 0. Khi đó, trên bảng sẽ chỉ còn lại toàn số 0.
2. Nếu thay 23 số bằng 25 số thì bài toán trên sẽ không thực hiện được.
Giải thích:
Ta có tổng các số từ 1 đến 25 = (1 + 25) x 25 : 2 sẽ là một số lẻ.
Giả sử, khi xoá đi hai số bất kỳ thì tổng các số trên bảng sẽ giảm đi là: (a + b) - (a - b) = 2b = một số chẵn.
Như vậy, sau một số bước xoá hai số bất kỳ thì tổng các số trên bảng vẫn còn lại là một số lẻ (số lẻ - số chẵn = số lẻ) và do đó trên bảng sẽ không phải là còn toàn số 0.


Bài 78/2001 - Cà rốt và những chú thỏ
(Dành cho học sinh Tiểu học)
Chú thỏ có thể ăn được nhiều nhất 120 củ cà rốt. Đường đi của chú thỏ như sau:
                                    14->12->13->14->13->16->15->10->13
Do đó, số củ cà rốt chú thỏ ăn được khi đi theo đường này là:
            14 + 12 + 13 + 14 + 13 + 16 + 15 + 10 + 13 = 120 (củ)


Bài 79/2001 - Về một ma trận số
(Dành cho học sinh THCS)
Bài này có rất nhiều nghiệm, để liệt kê tất cả các nghiệm thì phải sử dụng thuật toán duyệt. Do không gian tìm kiếm là cực kì lớn nên nếu duyệt tầm thường thì không thể giải đuợc, thậm chí còn không ra nghiệm nào cả. Vì vậy bài giải này duyệt bằng cách xây dựng một mảng ban đầu thoả mãn tích chất: dùng đúng 10 số 0, 10 số 1, ..., 10 số 9 và mỗi dòng không có quá 4 số khác nhau. Sau đó bằng cách hoán vị vòng các dòng để thoả mãn tính chất của đề bài.
Chọn mảng ban đầu như thế giảm đi rất nhiều khả năng và cũng làm mất đi rất nhiều nghiệm. Mảng ban đầu có thể có rất nhiều cách chọn, số nghiệm tìm ra phụ thuộc rất nhiều vào cách chọn này.
Ví dụ có thể chọn mảng ban đầu là:
(0,0,1,1,2,2,2,3,3,3)
(1,1,2,2,3,3,3,4,4,4)
(2,2,3,3,4,4,4,5,5,5)
(3,3,4,4,5,5,5,6,6,6)
(4,4,5,5,6,6,6,7,7,7)
(5,5,6,6,7,7,7,8,8,8)
(6,6,7,7,8,8,8,9,9,9)
(7,7,8,8,9,9,9,0,0,0)
(8,8,9,9,0,0,0,1,1,1)
(9,9,0,0,1,1,1,2,2,2)
Vì số nghiệm rất nhiều nên ta muốn ghi ra bao nhiêu nghiệm thì thay đổi biến sn để thay đổi số nghiệm cần ghi ra. Bài giải này in ra 100 nghiệm.
Các bạn chú ý rằng nếu có 1 bảng thoả mãn tính chất của bài thì tráo 2 dòng hoặc tráo 2 cột bất kì với nhau, hoặc quay 900 bảng ta có thể có các bảng cũng thoả mãn.
{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V+,X+}
{$M 65384,0,655360}
uses crt;
type        MG          = array[1..10,1..10]of integer;
               mg1c        = array[1..10]of integer;

const       N           =10;
               p            = 4;
               sn          =100; {số nghiệm muốn ghi ra}
               fo          ='out.txt';
               h           :MG= {một cách chọn khác}
                            ((0,0,0,1,1,1,2,2,2,3),
                            (1,1,1,2,2,2,3,3,3,4),
                            (2,2,2,3,3,3,4,4,4,5),
                            (3,3,3,4,4,4,5,5,5,6),
                            (4,4,4,5,5,5,6,6,6,7),
                            (5,5,5,6,6,6,7,7,7,8),
                            (6,6,6,7,7,7,8,8,8,9),
                            (7,7,7,8,8,8,9,9,9,0),
                            (8,8,8,9,9,9,0,0,0,1),
                            (9,9,9,0,0,0,1,1,1,2));

var         a,dx      : MG;
              lap        : mg1c;
              dem      : longint;
              f           : text;

procedure init;
var  k  :integer;
 begin
   dem:=0;
   a:=h;
   fillchar(dx,sizeof(dx),0);
   fillchar(lap,sizeof(lap),0);
   for k:=1 to N do lap[k]:=1;
   for k:=1 to N do dx[k,a[1,k]+1]:=1;
 end;

procedure ghikq(w:mg);
var i,j,ds:integer;
 begin
   inc(dem);
   writeln('****** :',dem,':******');
   writeln(f,'****** :',dem,':******');
   for i:=1 to N do
    begin
      for j:=1 to N do
        begin
          write(w[i,j]:2);
          write(f,w[i,j]:2);
        end;
      writeln;writeln(f);
    end;
 end;

function doi(k:integer):integer;
 begin
   if k mod N=0 then doi:=N
    else doi:=k mod N;
 end;

procedure try(k:byte;w:MG);
var i,j    :byte;
    luu    :mg1c;
    ldx    :mg;
    ok     :boolean;
 begin
   luu:=lap;ldx:=dx;
   for i:=1 to N do
     begin
       lap:=luu;dx:=ldx;
       for j:=1 to N do w[k,j]:=a[k,doi(i+j-1)];

       ok:=true;
       for j:=1 to N do
         begin
           inc(lap[j],1-dx[j,w[k,j]+1]);
           dx[j,w[k,j]+1]:=1;
           if lap[j]>4 then
             begin
               ok:=false;
               break;
             end;
         end;

        if ok then
          begin
            if k=N then
                ghikq(w)
              else try(k+1,w);
          end;
       if dem=sn then exit;
     end;
   lap:=luu;dx:=ldx;
 end;

BEGIN
  clrscr;
  init;
  assign(f,fo);
  rewrite(f);
  try(2,a);
  close(f);
END.
(Lời giải của Vũ Anh Quân)

Bài 80/2001 - Xếp số 1 trên lưới
(Dành cho học sinh THCS)
Bài toán có rất nhiều nghiệm, để liệt kê các nghiệm thì ta phải sử dụng thuật toán duyệt. Song duyệt thì rất lớn, mặt khác để ra được một cách điền thoả mãn thì không đơn giản chút nào (thời gian chạy sẽ rất lâu, thậm chí còn có thể bế tắc). Bài giải này duyệt theo một hướng tham lam có thể hiện ra được khá nhiều cách điền thoả mãn, tuy nhiên hướng giải này không hiện ra hết tất cả các nghiệm.
Hướng duyệt tham lam:
+ Mỗi dòng, mỗi cột có ít nhất một số 1.
+ Chia ma trận 10x10 thành 4 ma trận 5x5, mỗi ma trận 5x5 này sẽ được điền 4 số 1.
Cách kiểm tra tốt một ma trận sau khi điền có thoả mãn tính chất của bài không?
Duyệt cách chọn 5 hàng bất kì rồi xoá các số ở hàng đó, sau khi xoá xong ta tìm cách xoá 5 cột. Nếu sau khi xoá hàng xong mà cột nào còn số 1 thì phải xoá cột đó.
Nếu trong tất cả các cách xoá hàng, cột như vậy đều không xoá hết được thì bảng đó thoả mãn tính chất của bài.
Chương trình sau hiện ra 100 nghiệm.
{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R-,S+,T-,V+,X+}
{$M 16384,0,655360}
uses crt;
const        N  =10;
                p   =16;
                sn  =100;  {số nghiệm muốn hiện ra}
                fo  ='output.txt';
type         MG  =array[1..5,1..5] of byte;
var           a  : array[1..N,1..N] of integer;
                w : array[1..600] of MG;
                d  : array[1..5] of integer;
                c,dong,cc,ddd : array[0..N] of integer;
                ok : boolean;
                dem,sl : longint;
                s : MG;
                f : text;
procedure nap;
var i,j,k  : integer;
 begin
   for i:=1 to 5 do
     begin
       k:=0;
       inc(dem);
       for j:=1 to 5 do
        if i<>j then
          begin
            inc(k);
            w[dem,j]:=s[k];
          end;
     end;
 end;

procedure try(i:byte);
var j :byte;
 begin
   for j:=1 to 5 do
    if d[j]=0 then
      begin
        s[i,j]:=1;
        d[j]:=1;
        if i=4 then nap
         else try(i+1);
        d[j]:=0;
        s[i,j]:=0;
      end;
 end;
procedure kiemtra;
var i,j,use,k   :integer;
 begin
   cc:=c;
   for i:=1 to 5 do
    for j:=1 to N do dec(cc[j],a[dong[i],j]);
   use:=0;
   for k:=1 to N do inc(use,ord(cc[k]>0));
   if use<=5 then ok:=false;
 end;
procedure thu(i:integer);
var j     :integer;
 begin
   for j:=dong[i-1]+1 to N-5+i do
     begin
       dong[i]:=j;
       if i=5 then kiemtra
        else thu(i+1);
       if ok=false then exit;
     end;
 end;
procedure lam;
var i,j,x,y,u,v,k :integer;
 begin
   for i:=1 to dem do
     for j:=dem downto 1 do
      for x:=1 to dem do
       for y:=dem downto 1 do
         begin
            for u:=1 to 5 do
             for v:=1 to 5 do a[u,v]:=w[i,u,v];
            for u:=1 to 5 do
             for v:=1 to 5 do a[u,5+v]:=w[j,u,v];
            for u:=1 to 5 do
             for v:=1 to 5 do a[5+u,v]:=w[x,u,v];
            for u:=1 to 5 do
             for v:=1 to 5 do a[5+u,5+v]:=w[y,u,v];

            fillchar(c,sizeof(c),0);
            fillchar(ddd,sizeof(ddd),0);
            fillchar(dong,sizeof(dong),0);
            for u:=1 to N do
             for v:=1 to N do
               begin
                 inc(c[v],a[u,v]);
                 inc(ddd[u],a[u,v]);
               end;
            ok:=true;
            for k:=1 to N do
             if (c[k]=0)or(ddd[k]=0) then ok:=false;
            if ok then thu(1);
            if ok then
             begin
               inc(sl);
               writeln('*******:',sl,':*******');
               writeln(f,'*******:',sl,':*******');
               for u:=1 to N do
                  begin
                     for v:=1 to N do
                       begin
                         write(a[u,v],#32);
                         write(f,a[u,v],#32);
                       end;
                     writeln;writeln(f);
                  end;
               if sn=sl then exit;
             end;
         end;
 end;
BEGIN
  clrscr;
  fillchar(d,sizeof(d),0);
  fillchar(w,sizeof(w),0);
  fillchar(s,sizeof(s),0);
  dem:=0;sl:=0;
  try(1);
  assign(f,fo);
  rewrite(f);
  lam;
  close(f);
END.
(Lời giải của Đỗ Đức Đông)


Bài 81/2001 - Dãy nghịch thế
(Dành cho học sinh PTTH)
Program day_nghich_the;
uses crt;
const     fn = 'nghich.inp';
             gn = 'nghich.out';
             nmax=10000;
  var      f,g:text;
             n,i,j,dem:0..nmax;
            a,b,luu:array[1..nmax] of 0..nmax;
  procedure nhap;
    begin
      fillchar(a,sizeof(a),0); b:=a;
      assign(f,fn); reset(f);
      readln(f,n);
      for  i:=1  to n  do  read(f,a[i]);  write(f);
      for  i:=1  to n  do  read(f,b[i]);
      close(f);
    end;
  procedure tim_b;
    begin
       fillchar(luu,sizeof(luu),0);
       for  i:=1  to  n  do
       begin
           dem:=0;
           for  j:=i -1  downto  1  do
             if  a[i]<a[j] then  inc(dem);
           luu[a[i]]:=dem;
       end;
       for   i:=1  to  n  do  write(g,luu[i]:2);
       writeln(g);   writeln(g);
   end;
  procedure tim_a;
    begin
       fillchar(luu,sizeof(luu),0);
       for  i:=1  to  n  do
         if  b[i]>n-i  then   exit   else
           begin
             j:=0;
             dem:=0;
             repeat
                 inc(dem);
                 if  luu[dem]=0  then  j:=j+1;
             until  j>b[i];
             luu[dem]:=i;
           end;
       for  i:=1  to  n  do  write(g,luu[i]:2);
    end;
BEGIN  
      nhap;
      assign(g,gn);rewrite(g);
      tim_b;
      tim_a;
      close(g);
END.
(Lời giải của bạn Lê Thị Thu Thuý - Lớp 11A2 PTTH chuyên Vĩnh Phúc - thị xã Vĩnh Yên - tỉnh Vĩnh Phúc)


Bài 82/2001 - Gặp gỡ
(Dành cho học sinh PTTH)
Bài này có thể giải dễ dàng nhờ nhận xét sau:
- Nếu k robot ở các vị trí mà tổng toạ độ của chúng (x+y) có tính chẵn lẻ khác nhau thì chúng không bao giờ gặp nhau (vì chúng luôn luôn di chuyển, không có robot đứng yên). Như vậy, sau khi loại trường hợp trên, gọi A[t, i j] là số bước di chuyển ít nhất để robot t di chuyển từ vị trí ban đầu đến ô (i, j). Khi đó, số bước di chuyển ít nhất mà k robot phải di chuyển để gặp nhau là:
Min (max(A(t, i j) với 1 <= t <= k, 1 <= i <= M, 1 <= j <= N. Loang ngược lại, ta có đường đi của những robot này.
Cài đặt chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q-,R-,S+,T-,V+,X+,Y+}
{$M 16384,0,655360}
Program MEET;
Uses crt;
Type point = record
        x,y:integer;
        End;
Const   P:array[1..4,1..2] of integer=((0,1),(0,-1),(-1,0),(1,0));
            Q:string='LRDU';
            inp = 'MEET.INP';
            out = 'MEET.OUT';
Var  v: array[1..10] of point;
       A: array[1..10,0..51,0..51] of integer;
       B: array[0..51,0..51] of byte;
       t: array[0..1,1..750] of point;
       M,N,K,c,d,e,g,h,l,i,j,Min,Max:integer;
       s,st:string;
       f:text;
Procedure NoSolution;
Begin
   Write(' # ');Readln;Halt;
End;
Procedure Input;
Begin
   Assign(f,inp);Reset(f);
   Readln(f,m,n,k);
   If k>0 then
      Begin
         Readln(f,v[1].x,v[1].y);
         e:=(v[1].x+v[1].y) mod 2;
      End;
   For c:=2 to k do
      Begin
         Read(f,v[c].x,v[c].y);
         If (v[c].x+v[c].y) mod 2<>e then NoSolution;
      End;
   Fillchar(b,sizeof(b),1);
   For c:=1 to m do
      For d:=1 to n do read(f,B[c,d]);
   Close(f);
End;
Procedure Solve;
Var Stop:boolean;
    z:array[0..1] of integer;
Begin
   For c:=0 to m+1 do
      For d:=0 to n+1 do
         If b[c,d]=0 then
            For e:=1 to k do a[e,c,d]:=MaxInt else
            For e:=1 to k do a[e,c,d]:=-1;
   For c:=1 to k do
      Begin
         l:=1;g:=0;h:=1;z[0]:=1;z[1]:=0;
         t[0,1]:=v[c];a[c,v[c].x,v[c].y]:=0;
         Stop:=false;
         While not Stop do
            Begin
               Stop:=true;
               For d:=1 to z[g] do
                  For e:=1 to 4 do
                     Begin
                        i:=P[e,1]+t[g,d].x;
                        j:=P[e,2]+t[g,d].y;
                        If a[c,i,j]>l then
                           Begin
                              a[c,i,j]:=l;inc(z[h]);
                              t[h,z[h]].x:=i;
                              t[h,z[h]].y:=j;
                              Stop:=false;
                           End;
                     End;
               l:=l+1;g:=1-g;h:=1-h;z[h]:=0;
            End;
      End;
   Min:=MaxInt;
   For c:=1 to m do
      For d:=1 to n do
         If b[c,d]<>1 then
         Begin
            max:=a[1,c,d];
            For e:=2 to k do
               If Max<a[e,c,d] then Max:=a[e,c,d];
            If Min>Max then
               Begin
                  Min:=Max;
                  i:=c;j:=d;
               End;
         End;
   If Min=MaxInt then NoSolution;
   Assign(f,out);Rewrite(f);
   For e:=1 to k do
      Begin
         c:=i;d:=j;s:='';
         While A[e,c,d]>0 do
            Begin
               l:=1;
               While a[e,c+P[l,1],d+P[l,2]]+1<>a[e,c,d] do l:=l+1;
               s:=Q[l]+s;
               c:=c+P[l,1];d:=d+P[l,2];
            End;
         l:=l-1+2*(l mod 2);
         st:=s[1]+Q[l];
         For g:=1 to (min-a[e,i,j]) div 2 do s:=st+s;
         Writeln(f,s);
      End;
   Close(f);
End;
BEGIN
   Clrscr;
   Input;
   Solve;
   Write('Complete - Open file ',out,' to view the result');
   Readln
END.
(Lời giải của bạn Vũ Lê An - Lớp 12T2 - Lê Khiết - Quảng Ngãi)
Nhận xét: Bài làm của bạn Vũ Lê An phần kết quả còn thiếu trường hợp. Sau đây là một cách cài đặt khác song thuật toán cũng giống với Vũ Lê An.
Mở rộng bài toán: Cho một đồ thị gồm N đỉnh, có k con robot ở k đỉnh V1, V2,.., Vk. Sau mỗi đơn vị thời gian tất cả các con robot đều phải chuyển động sang các đỉnh kề với đỉnh nó đang đứng. Hãy tìm cách di  chuyển các con robot để chúng gặp nhau tại một điểm.
a. Trong đồ thị vô hướng
b. Trong đồ thị có hướng (k = 2 - Đề thi chọn đội tuyển Quốc gia)

{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V+,X+}
{$M 65384,0,655360}
program Bai82_gap_go;{Author  : Đỗ Đức Đông}
uses crt;
const       max            =50;
            max_robot      =10;
            fi             ='meet.inp';
            fo             ='meet.out';
            tx             :array[1..4]of integer=(0,-1,1,0);
            ty             :array[1..4]of integer=(-1,0,0,1);
            h              :string='LUDR';

var         a              :array[1..max,1..max]of byte;
            robot          :array[1..max_robot,1..2]of byte;
            l              :array[1..max,1..max,1..max_robot]of integer;
            q              :array[1..max*max,1..2]of byte;
            dau,cuoi,m,n,r :integer;
            best,mx,my     :integer;
            ok             :boolean;

procedure docf;
var  f    :text;
     k,i,j:integer;
 begin
    assign(f,fi);
    reset(f);
    readln(f,m,n,r);
    for k:=1 to r do readln(f,robot[k,1],robot[k,2]);
    for i:=1 to m do
     for j:=1 to n do read(f,a[i,j]);
    close(f);
 end;

procedure loang(k:integer);
var x,y,s,u,v  :integer;
 begin
   fillchar(q,sizeof(q),0);
   dau:=1;cuoi:=1;
   q[1,1]:=robot[k,1];
   q[1,2]:=robot[k,2];
   l[robot[k,1],robot[k,2],k]:=1;
   while dau<=cuoi do
     begin
        x:=q[dau,1];y:=q[dau,2];
        for s:=1 to 4 do
          begin
            u:=x+tx[s];
            v:=y+ty[s];
            if (u>0)and(v>0)and(u<=m)and(v<=n)and(a[u,v]=0)and(l[u,v,k]=0) then
              begin
                inc(cuoi);q[cuoi,1]:=u;q[cuoi,2]:=v;
                l[u,v,k]:=l[x,y,k]+1;
              end;
          end;
        inc(dau);
     end;
 end;

procedure lam;
var k,i,j :integer;
    meet  :boolean;
 begin
   fillchar(l,sizeof(l),0);
   ok:=true;
   for k:=2 to r do
    if (robot[1,1]+robot[1,2]+robot[k,1]+robot[k,2]) mod 2=1 then ok:=false;

   if ok then
    begin
      best:=maxint;
      for k:=1 to r do loang(k);
      for i:=1 to m do
       for j:=1 to n do
         begin
           meet:=true;
           for k:=1 to r do meet:=meet and (l[i,j,k]>0) and (l[i,j,k]<best);

           if meet then
             begin
               best:=0;
               for k:=1 to r do
                if l[i,j,k]>best then
                  begin
                    best:=l[i,j,k];
                    mx:=i;my:=j;
                  end;
             end;
         end;
      ok:=best<maxint;
    end;
 end;

procedure ghif;
var f        :text;
    k,kk     :byte;
    lap      :string;

 procedure viet(x,y:byte);
 var u,v,s :byte;
  begin
    for s:=1 to 4 do
      begin
        u:=x+tx[s];
        v:=y+ty[s];
        if (u>0)and(v>0)and(u<=m)and(v<=n)and(l[u,v,k]=l[x,y,k]-1) then
          begin
            if l[u,v,k]>1 then viet(u,v);
            write(f,h[5-s]);
            break;
          end;
      end;
  end;

 begin
   assign(f,fo);
   rewrite(f);
   if ok=false then write(f,'#')
    else
      begin
        for k:=1 to 4 do
          if (mx+tx[k]>0)and(my+ty[k]>0)and(mx+tx[k]<=m)and(my+ty[k]<=n) then
           if (a[mx+tx[k],my+ty[k]]=0) then kk:=k;
        lap:=h[kk]+h[5-kk];

        for k:=1 to r do
          begin
            if l[mx,my,k]>1 then viet(mx,my);
            for kk:=1 to (best-l[mx,my,k]) div 2 do write(f,lap);
            writeln(f);
          end;
      end;
   close(f);
 end;

BEGIN
  docf;
  lam;
  ghif;
END.

Bài 83/2001 - Các đường tròn đồng tâm
(Dành cho học sinh Tiểu học)
Đáp số: Các số được điền như sau:

Bài 84/2001 -  Cùng một tích
(Dành cho học sinh THCS và THPT)
Thuật toán: Gọi số lượng số xi =1 là a, số lượng số xi=-1 là b, số lượng số xi = 0 là c. Ta có: a+b+c=N.
Với mỗi giá trị c khác nhau ta có tương ứng một nghiệm. Nên số nghiệm bằng số giá trị mà c có thể nhận được. Nếu duyệt theo biến c thì có rất nhiều khả năng nên thay vì duyệt theo biến c ta duyệt theo a và b. Vai trò của các số bằng 1 và các số bằng -1 là như nhau nên ta có thể giả sử số lượng số bằng 1 lớn hơn số lượng bằng -1 (a>=b).
Vậy åxi = a-b và åxi2 = a+b (i = 1,..,N)
åxixj = P (i =1, ..., N; j =1, ..., N; i<>j) suy ra P =2*åxixj (i =1, ..., N -1; j =1, ..., N; i<j)
Ta có phương trình: (a+b)+p=(a-b)2
suy ra 0 <= (a-b) <= sqrt(a+b+p) <= sqrt(N+p)<[sqrt(2*1010)] = 44721.
Vậy ứng với mỗi giá trị (a-b) ta có một giá trị (a+b) và một giá trị c. Lần lượt thử với từng giá trị của (a-b) rồi kiểm tra xem a, b và c thoả mãn các tính chất không?
{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V+,X+,Y+}
{$M 16384,0,655360}
uses crt;
const      fi       ='input.txt';
              fo       ='output.txt';
var        n,p,  h :longint;
             dem    :longint;
              t         :real;
procedure docf;
var  f    :text;
 begin
    assign(f,fi);
    reset(f);
    read(f,n,p);
    close(f);
    dem:=0;
 end;
procedure lam;
var can :longint;
 begin
   can:=trunc(sqrt(2*n));
   for h:=0 to can do
    begin
     t:=h;
     t:=sqr(t)-p;
     if (t>=h)and(t<=n) then inc(dem);
    end;
 end;
procedure ghif;
var  f    :text;
 begin
   assign(f,fo);
   rewrite(f);
   writeln(f,dem);
   close(f);
 end;
BEGIN
  docf;
  if p mod 2=0 then lam;
  ghif;
END.
(Lời giải của Đỗ Đức Đông)


Bài 85/2001 - Biến đổi 0 - 1
(Dành cho học sinh THPT)
Thuật toán: Bài này sử dụng thuật toán duyệt nhưng có một vài chú ý sau:
- Với 1 ô ta chỉ tác động nhiều nhất một lần.
- Thứ tự tác động là không quan trọng.
- Với một ô có nhiều nhất 5 ô ảnh hưởng được tới nó, vì vậy nếu với một ô ta biết 4 ô ảnh hưởng của nó có được tác động hay không thì ô còn lại ta sẽ biết là có nên tác động hay không tác động.
Từ các chú ý trên ta sẽ duyệt một dòng 1 (hoặc một cột 1) được tác động như thế nào khi đó các ô ở dòng 1 (hoặc cột 1) sẽ chỉ còn 1 ô ảnh hưởng tới nó. Ta sẽ biết được rằng các ô dòng 2 (hoặc cột 2) cũng sẽ được tác động như thế nào, cứ như vậy cho các dòng tiếp theo.
Bài sẽ phải duyệt 2N nếu duyệt theo dòng 1 (2M  nếu duyệt theo cột 1) vì vậy để giảm độ phức tạp của bài bạn nên chọn duyệt theo chiều nào tuỳ thuộc vào M,N.
{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q-,R+,S+,T-,V+,X+}
{$M 16384,0,655360}
uses crt;
const       max   =100;
               fi   ='biendoi.inp';
               fo   ='biendoi.out';
               tx : array[0..4]of integer=(0,0,-1,0,1);
               ty: array[0..4]of integer=(0,-1,0,1,0);
type        mg = array[1..max,1..max]of byte;
var  a,b,td,lkq,c:mg;
       m,n,dem,best:integer;
procedure docf;
var  f    :text;
      i,j  :byte;
 begin
   assign(f,fi);
   reset(f);
   readln(f,m,n);
   for i:=1 to m do
    for j:=1 to n do read(f,a[i,j]);
   for i:=1 to m do
    for j:=1 to n do read(f,b[i,j]);
   close(f);
 end;
procedure tacdong(i,j:byte);
var u,v,k  :integer;
 begin
   for k:=0 to 4 do
     begin
       u:=i+tx[k];
       v:=j+ty[k];
       if (u>0)and(v>0)and(u<=m)and(v<=n) then a[u,v]:=1-a[u,v];
     end;
   inc(dem);
 end;
procedure process;
var i,j,k   :byte;
      w : mg;
 begin
   c:=a;dem:=0;w:=td;
   for i:=1 to n do
    if td[1,i]=1 then tacdong(1,i);
   for i:=2 to m do
    for j:=1 to n do
     if a[i-1,j]<>b[i-1,j] then
       begin
         tacdong(i,j);
         td[i,j]:=1;
       end;
   for k:=1 to n do
    if a[m,k]<>b[m,k] then begin a:=c;td:=w;exit;end;
   if dem<best then
     begin
       best:=dem;
       lkq:=td;
     end;
   a:=c;td:=w;
 end;
procedure try(i:byte);
var  j    :byte;
 begin
   for j:=0 to 1 do
     begin
       td[1,i]:=j;
       if i=n then process
        else try(i+1);
     end;
 end;
procedure ghif;
var f     :text;
    i,j   :integer;
 begin
   assign(f,fo);
   rewrite(f);
   if best<>maxint then
     begin
       writeln(f,best);
       for i:=1 to m do
        for j:=1 to n do
          if lkq[i,j]=1 then writeln(f,i,#32,j);
     end
   else writeln(f,'No solution');
   close(f);
 end;
begin
  clrscr;
  best:=maxint;
  docf;
  try(1);
  ghif;
end.
(Lời giải của Đinh Quang Huy)


Bài 86/2001 - Dãy số tự nhiên logic
(Dành cho học sinh Tiểu học)
Số đầu và số cuối cần tìm của dãy số logic đã cho là: 10 và 24.
Giải thích: dãy số đó là dãy các số tự nhiên liên tiếp không nguyên tố.


Bài 87/2001 - Ghi các số trên bảng
(Dành cho học sinh THCS)
Procedure bai87;
uses crt;
  var d, N:integer;
begin
  clrscr;
  write('Nhap so nguyen duong N: '); readln(N);
  repeat
      if N mod 2 = 0 then N:= div 2 else N:=N-1;
      d:=d+1;
  until N=0;
  write('So lan ghi so len bảng: ', d);
  readln;
End.
(Lời giải của bạn Cao Le Thang Long)

Bài 88/2001 - Về các số đặc biệt có 10 chữ số
(Dành cho học sinh THCS và THPT)
Thuật toán: mảng a[0..9] lưu kết quả, t[i] là số các chữ số i trong a. Theo bài ta có thể suy ra: a[0] + a[1] + ... + a[9] = số các chữ số 0 + số các chữ số 1 + ... + số các chữ số 9 = 10. Như vậy, ta dùng phép sinh đệ quy có nhánh cận để giải bài toán: ở mỗi bước sinh a[i], ta tính tổng các chữ số a[0]..a[i] (lưu vào biến s), nếu s >10 thì không sinh tiếp nữa. Sau đây là toàn bộ chương trình:
Procedure bai88;
const fo='bai88.out';
var a,t:array[0..9] of integer;
    i,s:integer;
    f:text;
procedure save;
  var i:integer;
begin
  for i:=0 to 9 do if a[i] <> t[i] then exit;
  for i:=0 to 9 do write(f,a[i]); writeln(f);
end;
procedure try(i:integer);
  var j:integer;
begin
  for j:= 0 to 9 do
  if ((i<j) or ((i>=j) and (t[j] +1 <=a[j]))) and (s<=10) then
  begin
     a[i]:=j;
     inc(t[j]);
     s:=s+j;
     if i<9 then try(i+1) else save;
     dec(t[j]);
     s:=s-j;
  end;
end;
BEGIN
  assign(f,fo);rewrite(f);
  for i:=1 to 9 do
  begin
    fillchar(t,sizeof(t),0);
    s:=0;
    a[0]:=i;
    s:=s+i;
    t[i]:=1;
    try(1);
  end;
  close(f);
END.
(Lời giải của bạn Nguyễn Chí Thức - Lớp 11A1 khối PTCTT - ĐHSP Hà Nội)


Bài 89/2001 - Chữ số thứ N
(Dành cho học sinh THCS và THPT)
Thuật toán: từ nhận xét rằng có 9 số có 1 chữ số, 90 số có 2 chữ số, ... Ta  sẽ xác định xem chữ số thứ N thuộc số có mấy chữ số và nó là số nào? Sau đó xem nó ở vị trí thứ mấy trong số đó.
Program bai89;
{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V+,X+}
{$M 16384,0,655360}
Uses crt;
Const      fi  ='number.inp';
              fo  ='number.out';
      cs:array[1..8] of longint = (9, 180, 2700, 36000, 450000, 5400000, 63000000, 720000000);
Var   n : longint;
          f,g :text;
Function num(n:longint):char;
  var k, so, mu : longint;
       s : string;
Begin
   k:=1; mu:=1;
   while (k<9)and(cs[k]<n) do
   begin
       n:=n-cs[k];
       inc(k); mu:=mu*10;
   end;
   if mu=1 then so:=n div k
    else so:=n div k+mu+ord(n mod k>0)-1;
   str(so,s);s:=s[k]+s;
   num:=s[n mod k+1];
End;
BEGIN
  assign(f,fi); reset(f);
  assign(g,fo); rewrite(g);
  while not seekeof(f) do
  begin
      readln(f,n);
      writeln(g,num(n));
  end;
  close(f);
  close(g);
END.
(Lời giải của bạn Lê Văn Đức - Nguyễn Huệ - Hà Đông - Hà Tây)

Bài 90/2002 - Thay số trong bảng 9 ô
(Dành cho học sinh Tiểu học)
Do tổng các số trong các ô điền cùng chữ cái ban đầu là bằng nhau nên ta suy ra: 2M = 3I = 4S.  Vì 4S chia hết cho 4, do đó 2M và 3I cũng chia hết cho 4.
Suy ra: I chia hết cho 4; M = 2S; 3I = 4S.
Đặt I = 4k (k = 1, 2,...), ta suy ra tương ứng: S = 3k, và M = 6k.
Ví dụ, với k = 1 ta có đáp số sau: I = 4, S = 3, M = 6; 
Với k = 2, ta có: I = 8, S = 6, M = 12; ...

Bài 91/2002 - Các số lặp
(Dành cho học sinh THCS và THPT)
Program bai91;
{Thuat toan lua bo vao chuong}
{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q-,R+,S+,T-,V+,X+}
{$M 16384,0,655360}
USES crt;
CONST M1 = MaxInt div 4 + 1;
             M2 = MaxInt;
              fi = 'Bai91.Inp';
TYPE MA = Array[0..M1] of LongInt;
Var A: Array[0..3] of ^MA;
       d,l  :LongInt;
Procedure Init;
  Var i:Byte;
Begin
 For i:=0 to 3 do
  begin
        New(A[i]);
        Fillchar(A[i]^,sizeof(A[i]^),0);
   end;
 End;
Procedure ReadF(k:ShortInt);
Var f:Text;
      x:LongInt;
      i,j:Integer;
Begin
    Init;
    Assign(f,fi);
    Reset(f);
    While Not SeekEof(f) do
     begin
           Read(f,x);
           x:=x*k;
           If x>=0 then
           begin
                i:=x div M1;
                j:=x mod M1;
                If i=4 then begin i:=3; j:=M1; end;
                Inc(A[i]^[j]);
                If A[i]^[j]>d then begin d:=A[i]^[j]; l:=x*k; end;
           end;
     end;
     Close(f);
     For i:=0 to 3 do Dispose(A[i]);
End;
BEGIN
  Clrscr;
  d:=0; l:=0;
 ReadF(-1);
 ReadF(1);
 Writeln('So lap nhieu nhat la: ',l,#10#13,'Voi so lan lap : ',d);
  Readln;
END.
(Lời giải của Nguyễn Toàn Thắng *)
Bài giải của bạn Nguyễn Toàn Thắng dùng thuật toán lùa bò vào chuồng. Sau đây là cách giải khác dùng thuật toán đếm số lần lặp.
Thuật toán: Tư tưởng thuật toán là dùng mảng đánh đấu có nghĩa là số x thì Lap[x] sẽ là số lần xuất hiện của số x trong mảng. Vì số phần tử của mảng nhỏ hơn hoặc bằng 106 nên phần tử của mảng Lap phải là kiểu dữ liệu để có thể lưu trữ được 106. Số x là số nguyên kiểu integer và do giới hạn bộ nhớ là 64K nên ta dùng ba mảng động như sau: MG = array[-maxint..maxint] of byte;
L[1..3] of ^MG;
Xử lý trong hệ cơ số 100.
Chương trình.
{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V+,X+,Y+}
{$M 16384,0,655360}
program bai91;{Đỗ Đức Đông}
uses crt;

const       fi          ='input.txt';
            fo          ='output.txt';
            coso        =100;

type        mg    =array[-maxint..maxint]of byte;

var         L    :array[1..3]of ^mg;
            n,lap       :longint;
            kq          :integer;
            time        :longint;
            clock       :longint absolute $00:$0046c;

procedure tao_test;
var  f    :text;
     k    :longint;
 begin
    n:=1000000;
    assign(f,fi);
    rewrite(f);
    writeln(f,n);
    for k:=1 to N do
     if random(2)=1 then write(f,random(maxint),#32)
      else write(f,-random(maxint),#32);
    close(f);
 end;

procedure danhdau(x:integer);
var i     :integer;
 begin
   for i:=3 downto 1 do
     if L[i]^[x]<coso then
       begin
         inc(L[i]^[x]);
         break;
       end
     else L[i]^[x]:=0;
 end;

procedure lam;
var  f    :text;
     k    :longint;
     x    :integer;
 begin
   for k:=1 to 3 do
     begin
       new(L[k]);
       fillchar(L[k]^,sizeof(L[k]^),0);
     end;
   assign(f,fi);
   reset(f);
   read(f,n);
   for k:=1 to n do
     begin
        read(f,x);
        danhdau(x);
     end;
   close(f);

   lap:=0;
   for k:=-maxint to maxint do
    if L[1]^[k]*sqr(coso)+L[2]^[k]*coso+L[3]^[k]>lap then
      begin
        lap:=L[1]^[k]*sqr(coso)+L[2]^[k]*coso+L[3]^[k];
        kq:=k;
      end;

   for k:=1 to 3 do dispose(L[k]);
 end;

procedure ghif;
var f     :text;
 begin
   assign(f,fo);
   rewrite(f);
   write(f,kq);
   writeln('So lan lap :',lap);
   close(f);
 end;

BEGIN
  {tao_test;}
  time:=clock;
  lam;
  ghif;
  writeln((clock-time)/18.2:10:10);
END.

Bài 92/2002 - Dãy chia hết
(Dành cho học sinh THPT)
program DayChiaHet;
uses crt;
const inp='div.inp';
      out='div.out';
var a:array[0..1] of set of byte;
    g:text;
    k,n,t,i,j,l:longint;
function f(x:longint):byte;
begin
   x:=x mod k;
   if x<0 then f:=x+k else f:=x;
end;
begin
 clrscr;
 assign(g,inp);reset(g);
 readln(g,n,k);
 t:=0;
 read(g,j);
 a[0]:=[f(j)];
 for i:=2 to n do
 begin
    t:=1-t;
    a[t]:=[];
    read(g,j);
    for l:=0 to k-1 do
     if l in a[1-t] then
     begin
        a[t]:=a[t]+[f(l+j)];
        a[t]:=a[t]+[f(l-j)];
     end;
 end;
 close(g);
 assign(g,out);rewrite(g);
 if 0 in a[t] then write(g,1) else write(g,0);
 close(g);
 write('Complete - Open file ',out,' to view the result');
 readln;
End.
(Lời giải của bạn Vũ Lê An - 12T2 - Lê Khiết - Quảng Ngãi)
Mở rộng bài toán:
1. Tìm dãy con liên tiếp có tổng bé nhất.
2. Tìm dãy con liên tiếp các phần tử thuộc dãy bằng nhau dài nhất.
3. Cho ma trận MxN hãy tìm hình chữ nhật có tổng lớn nhất (nhỏ nhất) với M,N<=100
4. Cho ma trận MxN hãy tìm hình chữ nhật có diện tích lớn nhất có các phần tử bằng nhau.
Cách giải bài toán 2 giải giống với bài toán 1, bài toán 3 và 4 giải giống nhau dựa trên cơ sở bài 1,2.
Cách giải bài toán 3: Xét hình các hình chữ nhật có toạ độ cột trái là i toạ độ cột phải là j (mất O(N2)). Coi mỗi dòng như một phần tử, để tìm hình chữ nhật có diện tích lớn nhất ta phải mất O(N) nữa. Như vậy độ phức tạp là O(N3).


Bài 93/2002  - Trò chơi bắn bi
(Dành cho học sinh Tiểu học)
Có 3 đường đi đạt số điểm lớn nhất là: 32.


Bài 94/2002 - Biểu diễn tổng các số Fibonaci

(Dành cho học sinh THCS)
Cách giải: Ta sẽ tìm số Fibonacci gần với số N nhất. Đây sẽ chính là số hạng đầu tiên nằm trong dãy kết quả. Sau đó, lấy hiệu của số N và số Fibonacci gần với số N nhất, tiếp tục tìm số Fib gần với hiệu trên và cứ thế cho đến khi hiệu đó là một số Fib. Kết quả các số Fibonacci sẽ được liệt kê theo thứ tự từ lớn đến nhỏ.
Chương trình:
Program BdFib;{Bai 94/2002: Bieu dien tong cac so Fibonacci}
uses crt;
var n:longint;
    f:array[1..1000] of longint;
function fib(k:integer): longint;
begin
     f[1]:=1;
     f[2]:=1;
     f[3]:=2;
     if f[k]=-1 then f[k]:=fib(k-1)+fib(k-2);
     fib:=f[k];
end;
procedure xuly;
var i,j:longint;
begin
     for i:=1 to 1000 do f[i]:=-1;
     while n>0 do
     begin
          i:=1;
          while fib(i)<=n do
          inc(i);
          j:=fib(i-1);
          write(j,' + ');
          n:=n-j;
     end;
     gotoxy(wherex-2,wherey);
     writeln(' ');
end;
procedure test;
begin
     clrscr;
     write('Nhap n='); readln(n);
     clrscr;
     write('n=');
     xuly;
end;
BEGIN
     test;
     readln;
END.

(Lời giải của bạn Cao Lê Thăng Long - Lớp 8E Nguyễn Trường Tộ - Hà Nội)

 


Bài 95/2002 - Dãy con có tổng lớn nhất

(Dành cho học sinh THPT)

Program subseq;
const  inp = 'subseq.inp';
          out = 'subseq.out';
var  n, dau, cuoi, d:longint;
       max, T:longint;
       f, g:text;
Procedure input;
begin
  assign(f,inp); reset(f);
  assign(g,out); rewrite(g);
  Readln(f,n);
End;
Procedure solve;
  var i,j:longint;
begin
  dau:=1; cuoi:=1; d:=1;
  max:=-maxlongint; T:=0;
  for i:=1 to n do
  begin
     readln(f,j); T:=T + j ;
    If T > max then
    begin
       max:=T;
       dau:=d; cuoi:=i;
    end;
    If T<0 then begin T:=0; d:=i+1; end;
  end;
End;
Procedure output;
Begin
  writeln(g,dau);
  writeln(g,cuoi);
  writeln(g,max);
  Close(f); Close(g);
End;
BEGIN
  input;
  solve;
  output;
END.
(Lời giải của bạn Võ Xuân Sơn - Lớp 11A2 THPT Phan Bội Châu - Nghệ An)

 


Bài 96/2002 - Số chung lớn nhất

(Dành cho học sinh THPT)
{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V+,X+}
{$M 16384,0,655360}
uses crt;
const   maxn   = 251;
        fi     = 'string.inp';
        fo     = 'string.out';
var  pa  : array[0..maxn,0..maxn] of byte;
     s1,s2,skq   :  string;
     max  :  byte;
procedure docf;
var  f : text;
begin
     assign(f,fi);
     reset(f);
     readln(f,s1);
     read(f,s2);
     close(f);
end;
function maxso(a,b:byte) : byte;
begin
     maxso := (abs(a-b)+a+b) div 2;
end;
procedure Idonotknow;
var  i,j : byte;
begin
     for i := length(s1) downto 1 do
         for j := length(s2) downto 1 do
             if s1[i] = s2[j]  then pa[i,j] := pa[i+1,j+1] +1
             else pa[i,j] := maxso(pa[i+1,j] , pa[i,j+1] );
     max := pa[1,1];
end;
procedure wastingtime;
var   ch           :  char;
      i,j,so,is,js :  byte;
begin
     is := 1; js := 1;
     so := 0;
     repeat
           for ch := '9' downto '0' do
               begin
                    i := is; j := js;
                    while (s1[i] <> ch)and(i <= length(s1))  do inc(i);
                    while (s2[j] <> ch)and(j <= length(s2))  do inc(j);
                    if pa[i,j] = max - so then
                       begin
                            skq := skq + ch;
                            is := i+1; js := j+1;
                            break;
                       end;
               end;
           inc(so);
     until max=so;
     while (skq[1] = '0')and(skq<>'0') do delete(skq,1,1);
end;
procedure ghif;
var       f    :        text;
begin
     assign(f,fo);
     rewrite(f);
     if max = 0 then write(f,' Khong co xau chung !!!...')
     else
         begin
              wastingtime;
              write(f,skq);
         end;
     close(f);
end;
BEGIN
     docf;
     idonotknow;
     ghif;
END.

Bài 97/2002 - Thay số trong bảng
(Dành cho học sinh Tiểu học)
4
5
6
 
                                             1       2       3
a
b
c
d
e
f
g
h
i
Ngang
4 - Bội số nguyên của 8;
5 - Tích của các số tự nhiên liên tiếp đầu tiên;
6 - Tích các số nguyên tố kề nhau
Dọc
1 - Bội nguyên của 11;
2 - Tích của nhiều thừa số 2;
3 - Bội số nguyên của 11.
Giải:
Từ (5) - Tích của các số tự nhiên đầu tiên cho kết quả là một số có 3 chữ số chỉ có thể là 120 hoặc 720 (1x2x3x4x5 = 120; 1x2x3x4x5x6 = 720).
Do đó, (5) có thể là 120 hoặc 720. Suy ra: f = 0; e = 2; d = 1 hoặc d = 7.
Tương tự, ta tìm được (6) có thể là 105 hoặc 385 (3x5x7 = 105; 5x7x11 = 385). Suy ra: i = 5; h = 0 hoặc h = 8; g = 1 hoặc g = 3.
Từ (4) suy ra c chỉ có thể là số chẵn. Do f = 0, i = 5, từ (3) ta tìm được c = 6.
Từ (2) - tích của nhiều thừa số 2 cho kết quả là một số có 3 chữ số chỉ có thể là một trong các số: 128, 256, 512. Mà theo trên e = 2 nên ta tìm được (2) là 128. Vậy b = 1, h = 8, g = 3.
Từ (4) - Bội số nguyên của 8, do đó ta có thể tìm được (4) có thể là một trong các số: 216, 416, 616, 816.
Tức là, a có thể bằng 2, 4, 6, hoặc 8. Kết hợp với (1), giả sử d = 1, như vậy ta không thể tìm được số nào thoả mãn (1).
Với d = 7, ta tìm được a = 4 thoả mãn (1).
Vậy a = 4, b = 1, c = 6, d = 7, e = 2, f = 0, g = 3, h = 8, i = 5.
Và ta có kết quả như sau:
4
1
6
7
2
0
3
8
5


Bài 100/2002 - Mời khách dự tiệc

(Dành cho học sinh THPT)
program Guest;
const
  Inp = 'Guest.inp';
  Out = 'Guest.out';
var
  n: Integer;
  lSum: LongInt;
  t, v, p, Pred, Ind: array[0..1005] of Integer;
  Value: array[0..1005] of LongInt;
  Ok: array[0..1005] of Boolean;
  procedure ReadInput;
  var
    hFile: Text;
    i: Integer;
  begin
    Assign(hFile, Inp);
    Reset(hFile);
    Readln(hFile, n);
    for i := 1 to n do Readln(hFile, t[i], v[i]);
    Close(hFile);
  end;
  procedure QuickSort(l, r: Integer);
  var
    i, j, x, tg: Integer;
  begin
    i := l; j :=r; x := p[(l + r) div 2];
    repeat
      while t[p[i]] < t[x] do Inc(i);
      while t[p[j]] > t[x] do Dec(j);
      if i <= j then
      begin
        tg := p[i]; p[i] := p[j]; p[j] := tg;
        Inc(i); Dec(j);
      end;
    until i > j;
    if i < r then QuickSort(i, r);
    if j > l then QuickSort(l, j);
  end;
  procedure Prepare;
  var
    i, j: Integer;
  begin
    FillChar(Value, SizeOf(Value), 0);
    FillChar(Ok, SizeOf(Ok), False);
    lSum := 0;
    for i := 1 to n + 1 do p[i] := i;
    t[n + 1] := n + 1;
    QuickSort(1, n);
    j := 2; Ind[0] := 1;
    for i := 1 to n do
    begin
      while t[p[j]] = i do Inc(j);
      Ind[i] := j - 1;
    end;
  end;
  function View(n: Integer): LongInt;
  var
    i, j: Integer;
    lSum1, lSum2: LongInt;
  begin
    lSum1 := 0; lSum2 := v[n];
    for i := Ind[n - 1] + 1 to Ind[n] do
    begin
      if Value[p[i]] = 0 then Value[p[i]] := View(p[i]);
      lSum1 := lSum1 + Value[p[i]];
      for j := Ind[p[i] - 1] + 1 to Ind[p[i]] do
      begin
        if Value[p[i]] = 0 then Value[p[i]] := View(p[j]);
        lSum2 := lSum2 + Value[p[j]];
      end;
    end;
    if lSum1 > lSum2 then
    begin
      View := lSum1;
      Pred[n] := n - 1;
    end
    else
    begin
      View := lSum2;
      Pred[n] := n - 2;
    end;
  end;
  procedure Calculator(n: Integer);
  var
    i, j: Integer;
  begin
    if Pred[n] = n - 2 then
    begin
      Ok[n] := True; Inc(lSum);
      for i := Ind[n - 1] + 1 to Ind[n] do
        for j := Ind[p[i] - 1] + 1 to Ind[p[i]] do Calculator(p[j])
    end
    else for i := Ind[n - 1] + 1 to Ind[n] do Calculator(p[i])
  end;
  procedure WriteOutput;
  var
    hFile: Text;
    i: Integer;
    sView: LongInt;
  begin
    Assign(hFile, Out);
    Rewrite(hFile);
    sView := View(p[1]);
    Calculator(p[1]);
    Writeln(hFile, lSum, ' ', sView);
    for i := 1 to n do
      if Ok[i] then Writeln(hFile, i);
    Close(hFile);
  end;
begin
  ReadInput;
  Prepare;
  WriteOutput;

end.