1 minute read

문제접근

dp와 누적합을 이용해야 합니다.
우선 객차에서의 손님의 수를 누적합으로 저장합니다.

int n; cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> t[i];
		t[i] += t[i - 1];
	}

이제 dp로 다음과 같은 원리를 사용하면 됩니다.
예제에서 처럼 두 객차만큼 끌 수 있다고 할때 제일 많은 손님을 끄는 경우를 구하는 코드는 다음과 같습니다.

for (int i = 1; i <= n; i++)
{
    dp[i] = max(dp[i - 1], (t[i] - t[i - s]));
}
//s는 소형 기관차가 최대로 끌 수 있는 객차의 수

지금 i에서의 s만큼의 객차를 끌고 갈때와 전에 구했던 것과 비교하는 것입니다.
그럼 dp[7]에서는 첫번째에서 가장 많이 끌고갈 수 있는 수를 알 수 있네요. 105입니다.
이를 응용해서 다음과 같은 코드로 하면 됩니다.

int dp[4][50001];

for (int i = 1; i <= 3; i++)
	{
		for (int j = i * s; j <= n; j++)
		{
			dp[i][j] = max(dp[i][j - 1], dp[i - 1][j - s] + (t[j] - t[j - s]));
		}
	}

이 코드를 실행시키면 다음과 같은 결과가 나옵니다.

//dp[4][50001]
//dp[1][1]~dp[3][7]
0 75 90 90 90 90 105
0 0 0 135 135 165 195
0 0 0 0 0 210 240

dp[i-1][j-s]즉 첫번째 기차가 끌고 갔기에 선택할 수 없는 부분입니다. 이미 i가 1일때

0 75 90 90 90 90 105

각 구간에서 끌고 갈 수 있는 최대로 초기화 되었기 때문에. j가 4면 j - s즉 4에서 끌고 갈 수 있는 객차 손님수 누적합에서 가져올 수 있습니다.
요약하면 원리는 이렇습니다.

지금까지 가장 많이 끌고간것 + j에서의 누적합

코드

#include <bits/stdc++.h> 
#define ll long long

using namespace std;
int t[50001];
int dp[4][50001];
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	int n; cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> t[i];
		t[i] += t[i - 1];
	}
	int s; cin >> s;
	for (int i = 1; i <= 3; i++)
	{
		for (int j = i * s; j <= n; j++)
		{
			dp[i][j] = max(dp[i][j - 1], dp[i - 1][j - s] + (t[j] - t[j - s]));
		}
	}
	cout << dp[3][n];
}

Leave a comment