Qaçış#10152

Qaçış (Həll təhlili)

— Bessinin ilk dəqiqə ərzində qaça biləcəyi maksimal məsafə olsun, bu şərtlə ki, bu dəqiqədən sonra onun yorğunluq əmsalı -a bərabər olsun.

Məşqin başlanğıcına qədər dəqiqə keçib, ona görə də dp[0] = 0 qəbul edirik.

-ni hesablamaq üçün iki variantı nəzərdən keçirək:

  1. Əgər ilk i - 1 dəqiqədən sonra Bessinin yorğunluq əmsalı artıq -a bərabərdirsə, o sadəcə daha bir dəqiqə istirahət edə bilər:

    dp[i] = dp[i - 1]
  2. Fərz edək ki, Bessi son dəqiqəni aşağıdakı kimi keçirib:

Bu dəqiqədən sonra yorğunluq əmsalı yenidən -a bərabər olur. Bu blokun başlanğıcına qədər Bessi artıq məşqin ilk i - 2k dəqiqəsini keçirib, ona görə də bu ana qədər onun qaça biləcəyi maksimal məsafə dp[i - 2k]-yə bərabərdir.

Blokun ilk dəqiqəsi ərzində Bessi qaçır və aşağıdakı məsafəni qət edir

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

burada

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

Sonrakı dəqiqə Bessi istirahət edir. İstirahət zamanı məsafə artmır, lakin yorğunluq əmsalı tədricən -a qədər azalır.

Beləliklə,

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)

Alqoritmin realizasiyası

İşçi massivləri elan edək:

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

Giriş məlumatlarını oxuyuruq.

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

massivinin prefiks cəmlərini hesablayırıq.

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

-ın başlanğıc qiymətini təyin edirik.

dp[0] = 0;

dp[1], dp[2], ..., dp[n] qiymətlərini ardıcıl olaraq hesablayırıq.

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

Əgər -ci dəqiqədə Bessi istirahət edirsə, onda dp[i] = dp[i - 1].

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

-ci dəqiqədə uzunluğu olan blok başa çatır ( dəqiqə qaçış və dəqiqə istirahət). Yorğunluq əmsalı -dən çox ola bilməz. Blokun özü bu dəqiqəyə sığmalıdır, ona görə də 2k \le i.

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

Son blokun ilk dəqiqəsində Bessinin qət etdiyi runSum məsafəsini hesablayırıq.

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

Cari üçün əldə edilmiş optimal məsafəni hesablayırıq və -nin qiymətini yeniləyirik.

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

Cavabı çap edirik.

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