Задача групування#1525

Задача групування (Розбір)

Нехай a_1, a_2, ..., a_n — задані чисел. Позначимо через F_{ik}~(i \ge k) суму всіх можливих добутків по чисел, вибраних серед перших чисел a_1, ..., a_i. Побудуємо наступну таблицю значень F_{ik}:

Для чотирьох чисел отримуємо:

Виконуються наступні рекурентні співвідношення:

F_{i1} = F_{(i-1)1} + a_i\\ F_{ii} = F_{(i-1) (i-1)} \cdot a_i, 1 \le i \le n \\ F_{ik} = F_{(i-1)k} + F_{(i-1) (k-1)} \cdot a_i, 1 \le i \le n, 1 < k < i

Наприклад,

Значення кожного наступного рядка обчислюються на основі значень попереднього, тому для збереження достатньо одного лінійного масиву розміром до . Перерахунок значень -го рядка слід виконувати з кінця: спочатку обчислюється F_{ii}, потім F_{i(i-1)} і так далі до F_{i1}. Усі обчислення необхідно проводити за модулем .

Приклад

Розглянемо перший тест. Побудуємо дві таблиці: в першій обчислення виконуються без модуля, а в другій — за модулем m = 10.

Наприклад,

Відповіддю є максимальне значення в четвертому рядку другої таблиці.

Реалізація алгоритму

Оголосимо лінійний масив , у якому будуть перераховуватися значення F_{ik}.

long long d[1000];

Вводимо кількість чисел та значення . Для кожного вхідного тесту попередньо обнуляємо масив . Перше число a_1 заносимо в .

while (scanf("%lld %lld",&n,&m), n + m > 0)
{
  memset(d,0,sizeof(d));
  scanf("%lld",&d[0]);

Далі вводимо значення x = a_{i+1}~(1 \le i < n) і перераховуємо значення F_{ik} для k = i, i - 1, ..., 1 за наведеними вище рекурентними формулами. Усі обчислення виконуються за модулем .

  for (i = 1; i < n; i++)
  {
    scanf("%lld",&x);
    d[i] = (d[i-1] * x) % m; 

    for (j = i - 1; j > 0; j--)
      d[j] = (d[j-1] * x + d[j]) % m;

    d[0] = (d[0] + x) % m;
  }

Знаходимо максимальне значення серед елементів масиву і зберігаємо його у змінній .

  res = 0;
  for (i = 0; i < n; i++)	   
    if (d[i] > res) res = d[i];

Виводимо результат.

  printf("%lld\n",res);
}