Біг#10152

Біг (Розбір)

Нехай — максимальна відстань, яку Бессі може пробігти за перші хвилин за умови, що після цих хвилин її коефіцієнт втоми дорівнює .

До початку тренування пройшло хвилин, тому покладемо dp[0] = 0.

Для обчислення розглянемо два варіанти:

  1. Якщо після перших i - 1 хвилин коефіцієнт втоми Бессі вже дорівнює , то вона може просто відпочити ще одну хвилину:

    dp[i] = dp[i - 1]
  2. Припустимо, що останні хвилин Бессі провела наступним чином:

Після цих хвилин коефіцієнт втоми знову стає рівним . До початку цього блоку Бессі вже провела перші i - 2k хвилин тренування, тому максимальна відстань, яку вона могла пробігти до цього моменту, дорівнює dp[i - 2k].

Протягом перших хвилин блоку Бессі біжить і долає відстань

d[i − 2k + 1] + d[i − 2k + 2] + ... + d[i - k] = sum[i - k] - sum[i - 2k],

де

sum[i] = d[1] + d[2] + ... + d[i]

Наступні хвилин Бессі відпочиває. За час відпочинку відстань не збільшується, а коефіцієнт втоми поступово зменшується до .

Таким чином,

dp[i] = \max\left(dp[i-1], \max_{\substack{1 \le k \le m \\ 2k \le i}} \left(dp[i-2k] + sum[i-k] - sum[i-2k]\right)\right)

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

Оголосимо робочі масиви:

#define MAX 10001
int d[MAX], sum[MAX], dp[MAX];

Зчитуємо вхідні дані.

scanf("%d %d", &n, &m);
for (i = 0; i < n; i++)
  scanf("%d", &d[i]);

Обчислюємо префіксні суми масиву .

sum[0] = 0;
for (i = 1; i <= n; i++)
  sum[i] = sum[i - 1] + d[i - 1];

Ініціалізуємо початкове значення .

dp[0] = 0;

Послідовно обчислюємо значення dp[1], dp[2], ..., dp[n].

for (i = 1; i <= n; i++)
{

Якщо на хвилині Бессі відпочиває, то dp[i] = dp[i - 1].

  dp[i] = dp[i - 1];

На хвилині завершується блок довжини ( хвилин бігу та хвилин відпочинку). Коефіцієнт втоми не може перевищувати . Оскільки сам блок повинен вміщатися в ці хвилин, то 2k \le i.

  for (k = 1; k <= m && 2 * k <= i; k++)
  {

Обчислюємо відстань runSum, яку Бессі пробігла за перші хвилин останнього блоку.

    int runSum = sum[i - k] - sum[i - 2 * k];

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

    int temp = dp[i - 2 * k] + runSum;
    if (temp > dp[i]) dp[i] = temp;
  }
}

Виводимо відповідь.

printf("%d\n", dp[n]);