====== Intervals ====== اعداد ‎$a_1$‎ ، ‎$a_2$‎ تا ‎$a_n$‎ به شما داده شده است ، شما باید حداکثر ‎$k$‎ بازه به طول کم‌تر یا مساوی ‎$d$‎ از اعداد را انتخاب کنید به طوری که جمع اعداد درون بازه‌ها بیشینه شود و هر عدد در حداکثر یک بازه باشد‎.‎ ===== ورودی ===== * در سطر اول ورودی سه عدد ‎$1 \leq n \leq 1000$‎ ، ‎$1 \leq d \leq n$‎ و ‎$1 \leq k \leq n$‎ آمده است‎.‎ * در سطر بعدی ‎$n$‎ عدد ‎$a_1$‎ تا ‎$a_n$‎ آمده‌اند‎.‎ * تمام اعداد ورودی بزرگتر یا مساوی صفراند و جمع اعداد در int‎ جا می شود‎.‎ ===== خروجی ===== در تنها سطر خروجی جمع اعداد درون بازه‌ها را چاپ نمایید. ===== محدودیت‌ها ===== * محدودیت زمان: ۲ ثانیه * محدودیت حافظه: ۲۵۶ مگابایت ===== ورودی و خروجی نمونه ===== ^ ورودی نمونه ^ خروجی نمونه ^ |‎5 1 2‎ \\ ‎1 5 2 4 3‎ |‎9 ‎| |5 2 1‎ \\ 1 5 2 4 3 |‎7‎ | <پاسخ> با توجه به نوع سؤال، اولین راه‌حلی که به ذهن می‌رسد، استفاده از برنامه‌سازی پویاست، بدین شکل که dp[i][j]‎ را برابر مقدار زیر تعریف کنیم‎: بیشینه جمع اعداد درون بازه‌ها، به شرطی که اعداد درون بازه‌ها از ‎$i$‎ عدد اول باشند و تعداد بازه‌ها ‎$j$‎ تا باشد.برای به‌دست آوردن مقدار ‎dp[i][j]‎، دو حالت را در نظر می‌گیریم: ‎ - عدد ‎$i$‎ ام در هیچ بازه‌ای قرار نداشته باشد: در این صورت، مقدار بهینه برابر ‎dp[i–1][j]‎ می شود. - عدد ‎$i$‎ ام در بازه ی آخر قرار داشته باشد: در این صورت اگر قرار باشد خانه‌ی اول بازه‌ی آخر، عدد ‎$k$‎ام باشد، مقدار بهینه از عبارت زیر بدست می‌آید: ‎$\max_{(i-d \leq k < i)}{dp[k][j-1]‎+ ‎\sum_{t=k+1}^i a_t}$‎ محاسبه‌ی dp[i][j]‎ در حالت اول، از ‎$O(1)$‎ زمان می‌برد، اما در حالت دوم از ‎$O(n)$‎ زمان نیاز دارد. بنابراین کل الگوریتم در زمان ‎$O(n^3)$‎ اجرا می‌شود که با توجه به محدودیت ‎$n < 1001$‎ نیاز به بهبود الگوریتم داریم‎.‎ پیچیدگی زمانی الگوریتم‌های پویا را می‌توان ناشی از دو عامل دانست. اول تعداد وضعیت های موجود و دوم زمانی که صرف محاسبه‌ی مقدار هر وضعیت (که به آن بروزرسانی وضعیت هم می‌گویند) می‌شود. در الگوریتم بالا تعداد وضعیت ها از ‎$O(n^2)$‎ است و بروزرسانی هر وضعیت از ‎$O(n)$‎ انجام می‌شود. بنابراین کل الگوریتم از ‎$O(n^3)$‎ است. برای بهبود پیچیدگی زمانی الگوریتم باید یکی از این دو عامل را بهتر کنیم. در اینجا ما با بهتر کردن زمان بروزرسانی برای هروضعیت الگوریتم خود را سریع‌تر می‌کنیم‎. اگر sum[i]‎ را مجموع اعداد اول تا ‎$i$‎ ام دنباله تعریف کنیم، می‌توانیم عبارت بالا را به شکل زیر بازنویسی کنیم: ‎$\max_{i-d \leq k < i}(dp[k][j-1]‎+ ‎\sum_{t=k+1}^i a_t) =$‎ ‎$\max_{i-d \leq k < i}(dp[k][j-1]‎+ ‎sum[i]‎- ‎sum[k]) =$‎ ‎$sum[i]‎+ ‎\max_{i-d \leq k * [[سوال ۵۴|سوال بعد]] * [[سوال ۵۲|سوال قبل]]