Описание
Задан круг, разделенный на N секторов, и два целых числа М и К. В каждый из секторов круга помещается одно целое число, не меньшее К. Когда секторы заполнены числами, из них можно получать новые числа по следующим правилам:

  • взять число из одного сектора,

  • взять число, равное сумме двух или более чисел в смежных секторах

Из новых чисел составляется наибольшая последовательность подряд идущих чисел, начинающаяся с числа М: (М, М+1, М+2, ..., I ).

Пример на рис. 2.3 показывает, как получить все новые числа от 2 до 21 для приведенных на нем чисел в секторах. Песочным цветом выделены суммируемые числа

Задание
Напишите программу, которая определяет способ расстановки чисел в секторах, максимизирующий длину указанной последовательности.


Входные данные
Входной файл содержит три целых числа N, М и К (N 6, M 20, 0 K 20).

Выходные данные
Выведите в первую строку выходного файла наибольшее число
I для неразрывной последовательности новых чисел от М до I, которая может быть получена из чисел в секторах. Далее выведите все наборы чисел в секторах, из которых можно получить такую последовательность. Каждый набор записывается в отдельную строку выходного файла в виде списка чисел, начинающегося с наименьшего из них (оно может быть не единственным). Числа в списке должны идти в том же порядке, в котором они записаны в секторах круга. Если наименьшее число встречается несколько раз, следует вывести все возможные комбинации. Например, (1 1 2 3), (1 2 3 1), (1 3 2 1) и (1 1 3 2)


Например:

GOCIRCLE.IN
5
2
1


GOCIRCLE.OUT
21
1 3 10 2 5
1 5 2 10 3
2 4 9 3 5
2 5 3 9 4






Комментарии
Пусть, для определенности, минимальное из чисел находится в первом секторе. Очевидно, что это число должно принадлежать интервалу от К до М (если К>М, то задача решений не имеет). Пусть S[
i] - число в i-ом секторе. Задачу можно решать с помощью рекурсивного алгоритма расстановки чисел в секторах: на каждом шаге заполняется очередной сектор, корректируется множество новых чисел, которые можно получить, и осуществляется переход к следующему сектору. Какие числа мы можем ставить в секторы? В условии задачи сказано, что они обязаны быть не меньше К, но ничего не говорится о верхней границе.

Пусть N -1 секторов круга заполнено числами, а какой-то один пуст. Легко заметить, что мы, не используя этот сектор, можем получить не более, чем (N-1)/2 различных новых чисел. Обозначим через X первое число из последовательности М, М+1,..., которое мы не сможем получить. Понятно, что в оставшийся пустым сектор не имеет смысла ставить число, большее X. Поскольку Х не превосходит (N-1)/2+M, то последнее выражение является верхней границей на числа в секторах. Если S[1]<M, то эту границу можно уменьшить еще на 1. В секторы с номерами 2,3,...,N нужно помещать числа, не меньшие S[1], - это будет нижней границей

Для последнего сектора рассматриваемый диапазон чисел можно еще уменьшить. В качестве нижней границы (если N>2) можно взять число S[2] для того, чтобы исключить симметричные варианты, а в качестве верхней - то число X, о котором мы говорили выше. Если при этом сумма чисел, стоящих в секторах 1,...,N-1, и числа Х меньше наилучшего из найденных значений, то при любом варианте заполнения последнего сектора новое решение мы не получим.

Еще одно наблюдение. Пусть М<2К. Тогда числа М, М+1,...,2К-1 не могут быть получены как сумма чисел из нескольких (более одного) секторов, следовательно, либо (если 2K-M N) все они должны находиться в круге, либо (если 2K-M>N) в круге должны находиться числа М, М+1,...,M+N-1 и только они


Для ускорения работы программы введем матрицу Sum размера N×N, элемент Sum[
i,j] которой будет равняться сумме чисел в j последовательных секторах, начиная с сектора i (если, конечно, все они уже заполнены). К моменту заполнения очередного сектора р у нас должны быть сформированы текущее множество S новых чисел, которые можно образовать, и числа Sum[i,j] (1 i<p, i+j p). После заполнения сектора р (при переходе к следующему сектору) необходимо вычислить числа Sum[i, p-i+1] (1 i р) и включить их в множество S

Если сектор последний (р=N), то вычисляем и оставшиеся элементы матрицы Sum, также занося их в множество S. Затем для получившегося набора чисел в секторах нужно найти число
I из условия задачи и сравнить его с максимальным из ранее найденных (MaxI). Если I=MaxI, то добавляем набор к списку решений, если же I>MaxI, то очищаем список решений, вносим в него найденный набор и обновляем значение MaxI

При выводе результата для каждого из найденных решений с S[2]<S[N] нужно выдать также симметричное ему решение с S[2]>S[N], полученное путем зеркального отражения относительно биссектрисы первого сектора



Решение

{$A+,B-,D+,E+,F-,G+,I+,L+,N-,O-,P-,Q-,R-,S-,T-,V-,X+}
 
{$M 65520,0,655360} 
 
{$DEFINE GenAnswer} 
 
program gocircle; 
const NMax=6; 
      MMax=20; 
type O=array[1..Nmax] of byte; 
     Sums=array[1..NMax,1..NMax] of byte; 
     Sets=Set of byte; 
var N,M,K,Max,Num,Need,Up:integer; 
    A:O; 
    Best:array[1..100] of O; 
    Sum:Sums; 
    S,S1:Sets; 
 
Procedure Init; 
Begin 
  Close(input); 
  Assign(input,'gocircle.in'); ReSet(input); 
  read(N,M,K); 
  FillChar(A,SizeOf(A),0); 
End(*Init*)
 
Procedure Check; 
Var i,j:integer; 
Begin 
  For i:=3 to N do 
    For j:=N-i+2 to N-1 do 
      Begin 
        Sum[i,j]:=Sum[i,j-1]+A[j-N+i-1]; 
        Include(S1,Sum[i,j]) 
      End
 
  i:=M; 
  While i in S1 do inc(i); 
 
  If i>Max then 
    Begin 
      Num:=1; 
      Best[Num]:=A; 
      Max:=i 
    End 
  Else 
    If i=Max then 
      Begin 
        inc(Num); 
        Best[Num]:=A 
      End 
End(*Check*)
 
Procedure AddSum(k:integer); 
Var i:integer; 
Begin 
  Sum[k,1]:=A[k]; 
  Include(S1,A[k]); 
  For i:=k-1 downto 1 do 
    Begin 
      Sum[i,k-i+1]:=Sum[i,k-i]+A[k]; 
      Include(S1,Sum[i,k-i+1]) 
    End
End(*AddSum*)
 
Function NewUp(k:integer):integer; 
Var i:integer; 
Begin 
  If k then NewUp:=Up 
  Else 
   Begin 
     i:=M; 
     While i in S1 do inc(i); 
     NewUp:=i 
   End 
End(*NewUp*)
 
Procedure Solving(k:integer); 
Var i,Down,Need_,Up:integer; 
    S1_,S_:Sets; 
    Sum1:Sums; 
Begin 
  If k=N+1 then 
    Begin 
      Check; 
      Exit 
    End
 
  If k=N then Down:=A[2] 
  Else Down:=A[1]; 
 
  Up:=NewUp(K); 
  If (k=N) and (Sum[1,N-1]+Up then 
    Exit; 
 
  S1_:=S1; 
  Sum1:=Sum; 
  Need_:=Need; 
  S_:=S; 
 
  For i:=Down to Up do 
    If (Need>0) and ((N-k+1)<=Need) and (i in S) or 
       (Need=0) or (N-k+1>Need) then 
      Begin 
        A[k]:=i; 
        If (i in S) then 
          Begin 
            dec(Need); 
            Exclude(S,i) 
          End
 
        AddSum(k); 
        Solving(k+1); 
 
        Need:=Need_; 
        S:=S_; 
        S1:=S1_; 
        Sum:=Sum1 
      End
End(*Solving*)
 
Procedure Solve; 
Var i:integer; 
Begin 
  Max:=M-1; 
  Up:=N*(N-1) div 2+M-1; 
  Num:=0; 
  FillChar(Sum,SizeOf(Sum),0); 
 
  For i:=K to M do 
    Begin 
      A[1]:=i; 
      Sum[1,1]:=i; 
      Need:=2*i-M; 
      If Need<0 then Need:=0; 
      If Need>0 then S:=[M..2*i-1]; 
      If (i=M) and (Need>0) then 
        Begin 
          dec(Need); 
          Exclude(S,M) 
        End
 
      S1:=[i]; 
      If i<>M then dec(Up); 
      Solving(2); 
      If i<>M then inc(Up) 
    End
End(*Solve*)
 
Procedure Done; 
Var i,j:integer; 
Begin 
  Close(input); Close(output); 
  Assign(output,'gocircle.out'); ReWrite(output); 
 
{$IFDEF GenAnswer} 
  writeLn(2*Num); 
{$ENDIF} 
 
  writeln(Max-1); 
  For i:=1 to Num do 
    Begin 
      For j:=1 to N do write(Best[i,j],' '); 
      writeln; 
      write(Best[i,1],' '); 
      For j:=0 to N-2 do write(Best[i,N-j],' '); 
      writeln 
    End
 
  Close(output) 
End(*Done*)
 
BEGIN 
  Init; 
  Solve; 
  Done 
END.


© Особенности национальных задач по информатике