Notice
Recent Posts
Recent Comments
Link
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Archives
Today
Total
관리 메뉴

dh-winternagi 님의 블로그

(5977) Mowing the Lawn 본문

백준 (C++)/Solve

(5977) Mowing the Lawn

dh-winternagi 2026. 4. 21. 18:26

https://www.acmicpc.net/problem/5977

단계별로 풀어보기

38단계(스택, 큐, 덱 2) 7번째

 

 

 

수열 중 일부를 선택했을 때 최대값을 찾는 문제. 단 연속해서 k개를 초과하여 선택할 수 없다.

수열의 전체 합은 일정하므로 선택한 값이 최대가 된다는 것은 선택하지 않은 값이 최소가 된다는 것이다.

다시 말해 간격이 k+1개 이하가 되도록 선택했을 때 최소값을 찾는 문제와 동치이다.

dp[x]를 x번 소를 선택했고 조건을 만족시키는 최소값으로 정의하자. 이때 dp의 점화식은 아래와 같다.

dp[0]= 0: 소를 선택하지 않으면 최소값은 0이다.

(1≤x≤k+1)  dp[x]= v[x]: x번 소를 선택했다면 1번~x-1번 소는 선택하지 않아도 조건을 만족한다.

(k+1<x≤N) dp[x]= v[x]+min(dp[y])(x-k-1≤y≤x-1): x-k-1~x-1번 소 중 하나를 선택해야 조건을 만족하므로 구간 내 dp값 중 최소값을 더해야 한다.

여기서 min(dp[y])를 덱 최대값 트릭을 이용해 빠르게 구하면 된다.

조건을 만족하려면 n-k~n번 소 중 하나를 선택해야 하므로 DP값 갱신이 끝난 뒤 dp[n-k]~dp[n]중 최소값(dp[0]=0으로 n=k일 때 예외처리도 되어있음)을 찾아 전체 총합에서 빼주면 된다.

사실 dp[n-k]~dp[n]는 탐색 과정에서 덱에서 정렬되었으므로 따로 찾을 필요 없이 덱 맨 앞을 가져오면 되는데, 대신 이때는 n=k 예외처리를 해줘야 한다.

 

 

 

#include <iostream>
#include <vector>
#include <deque>
using namespace std;

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  
  int n, k;
  long tot= 0, res= 100000000000000;
  
  cin >> n >> k;
  
  vector<int> v(n+1);
  vector<long> dp(n+1);
  
  for(int i=1;i<=n;i++){
    cin >> v[i];
    tot+= v[i];
  }
  
  deque<int> dq;
  
  for(int i=1;i<=n;i++){
    dp[i]= (i<=k+1 ? v[i] : dp[dq.front()]+v[i]);
    
    while(!dq.empty() && dp[dq.back()]>dp[i])  dq.pop_back();
    
    dq.push_back(i);
    
    while(dq.front()<i-k)  dq.pop_front();
  }
  
  for(int i=n-k;i<=n;i++)  res= min(res, dp[i]);
  
  // cout << tot-dp[dq.front()];로 해도 n!=k일 때 성립함
  cout << tot-res;
  
  return 0;
}

 

 

 

그리고 중요하진 않지만 DP 갱신에 필요한 데이터는 덱에 들어있기 때문에 굳이 DP배열를 선언하지 않을 수 있다.

#include <iostream>
#include <deque>
using namespace std;

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  
  int n, k;
  long tot= 0;
  
  cin >> n >> k;
  
  deque<pair<long,int>> dq;
  
  for(int i=0;i<n;i++){
    int e;
    
    cin >> e;
    
    long val= (i<k+1 ? e : dq.front().first+e);
    tot+= e;
    
    while(!dq.empty() && dq.back().first>val)  dq.pop_back();
    
    dq.push_back({val,i});
    
    while(dq.front().second<i-k)  dq.pop_front();
  }
  
  cout << tot-(n==k ? 0 : dq.front().first);
  
  return 0;
}

'백준 (C++) > Solve' 카테고리의 다른 글

(33918) 맛있는 스콘 만들기  (0) 2026.04.21
(15678) 연세워터파크  (0) 2026.04.21
(11003) 최솟값 찾기  (0) 2026.04.21
(3015) 오아시스 재결합  (0) 2026.04.21
(1725) 히스토그램  (0) 2026.04.21