Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

63-9kyo-hwang #218

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

63-9kyo-hwang #218

wants to merge 6 commits into from

Conversation

9kyo-hwang
Copy link
Collaborator

@9kyo-hwang 9kyo-hwang commented Sep 3, 2024

πŸ”— 문제 링크

ꡬ간 λ‚˜λˆ„κΈ° 2

βœ”οΈ μ†Œμš”λœ μ‹œκ°„

1μ‹œκ°„ νŠΈλΌμ΄ν•˜κ³  레퍼런슀 확인

✨ μˆ˜λ„ μ½”λ“œ

1. 문제

N개의 수둜 이루어진 1차원 배열이 μžˆλ‹€. 이 배열을 M개 μ΄ν•˜μ˜ κ΅¬κ°„μœΌλ‘œ λ‚˜λˆ„μ–΄μ„œ κ΅¬κ°„μ˜ 점수의 μ΅œλŒ“κ°’μ„ μ΅œμ†Œλ‘œ ν•˜λ €κ³  ν•œλ‹€. ꡬ간은 λ‹€μŒκ³Ό 같은 쑰건을 λ§Œμ‘±ν•΄μ•Ό ν•œλ‹€.

  1. ν•˜λ‚˜μ˜ ꡬ간은 ν•˜λ‚˜ μ΄μƒμ˜ μ—°μ†λœ μˆ˜λ“€λ‘œ 이루어져 μžˆλ‹€.
  2. λ°°μ—΄μ˜ 각 μˆ˜λŠ” λͺ¨λ‘ ν•˜λ‚˜μ˜ ꡬ간에 ν¬ν•¨λ˜μ–΄ μžˆμ–΄μ•Ό ν•œλ‹€.

κ΅¬κ°„μ˜ μ μˆ˜λž€ ꡬ간에 μ†ν•œ 수의 μ΅œλŒ“κ°’κ³Ό μ΅œμ†Ÿκ°’μ˜ 차이이닀.

예λ₯Ό λ“€μ–΄, 배열이 [1, 5, 4, 6, 2, 1, 3, 7] 이고, M = 3인 κ²½μš°κ°€ μžˆλ‹€.

μ΄λ•Œ, [1, 5], [4, 6, 2], [1, 3, 7]둜 ꡬ간을 λ‚˜λˆ„λ©΄ 각 κ΅¬κ°„μ˜ μ μˆ˜λŠ” 4, 4, 6점이 λœλ‹€. μ΄λ•Œ, μ΅œλŒ“κ°’μ€ 6점이닀.

λ§Œμ•½, [1, 5, 4], [6, 2, 1], [3, 7]둜 ꡬ간을 λ‚˜λˆ„μ—ˆλ‹€λ©΄, 각 κ΅¬κ°„μ˜ μ μˆ˜λŠ” 4, 5, 4점이 되고, μ΄λ•Œ μ΅œλŒ“κ°’μ€ 5점이 λœλ‹€.

두 경우 μ€‘μ—μ„œ μ΅œλŒ“κ°’μ΄ μ΅œμ†ŒμΈ 것은 5점인 것이고, 5점보닀 μ΅œλŒ“κ°’μ„ μž‘κ²Œ λ§Œλ“œλŠ” 방법은 μ—†λ‹€.

λ°°μ—΄κ³Ό M이 μ£Όμ–΄μ‘Œμ„ λ•Œ, κ΅¬κ°„μ˜ 점수의 μ΅œλŒ“κ°’μ˜ μ΅œμ†Ÿκ°’μ„ κ΅¬ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€.

2. 풀이

M개 μ΄ν•˜μ˜ κ΅¬κ°„μœΌλ‘œ 배열을 λ‚˜λˆ μ•Ό ν•˜λŠ”λ°, 이λ₯Ό λ¬΄μ‹ν•˜κ²Œ λ‹€ 닀루기엔 경우의 μˆ˜κ°€ λ„ˆλ¬΄ λ§Žλ‹€. λ‹¨μˆœνžˆ M이 μ΅œλŒ€ NκΉŒμ§€ 가기도 ν•˜κ³ , 심지어 M "μ΄ν•˜"이기 λ•Œλ¬Έμ— 경우의 μˆ˜λŠ” 폭발적으둜 λŠ˜μ–΄λ‚œλ‹€.

λ¬Έμ œμ—μ„œ κ΅¬ν•˜κ³ μž ν•˜λŠ” 건 ꡬ간 점수 μ΅œλŒ€κ°’ 쀑 μ΅œμ†Œκ°’μΈλ°, μ—¬κΈ°μ„œ ꡬ간 점수(ν•΄λ‹Ή κ΅¬κ°„μ˜ μ΅œλŒ€κ°’ - μ΅œμ†Œκ°’)에 μ£Όλͺ©ν•œλ‹€.

이 점수 차이λ₯Ό νƒμƒ‰μ˜ key둜 ν•˜μ—¬, "전체 배열을 M개 μ΄ν•˜λ‘œ λΆ„ν• ν•  수 μžˆλŠ”" 것듀 쀑 κ°€μž₯ μž‘μ€ 점수λ₯Ό ꡬ해내면 정닡이닀. 이 λ•Œ "이진 탐색"으둜 μˆ˜ν–‰ν•œλ‹€. 그러면 μ‹œκ°„ λ³΅μž‘λ„λŠ” $Nlog(N)$으둜 μΆ©λΆ„νžˆ ν•΄κ²° κ°€λŠ₯ν•˜λ‹€.

int N, M; cin >> N >> M;

vector<int> Nums(N);
for(int& Num : Nums)
{
    cin >> Num;
}

int Min = 0, Max = *max_element(Nums.begin(), Nums.end());
int Score = Max;

κ΅¬κ°„μ˜ 점수 μ°¨μ΄λŠ” μ΅œμ†Œ 0점(ꡬ간 λ‚΄ λͺ¨λ“  μˆ«μžκ°€ 동일함)λΆ€ν„° μ΅œλŒ€ 9999점(λ°°μ—΄μ˜ μˆ˜λŠ” μ΅œμ†Œ 1, μ΅œλŒ€ 10000)이닀. 이 λ²”μœ„ λ‚΄μ—μ„œ νƒ€κ²Ÿ 점수λ₯Ό μ°Ύμ•„λ³Έλ‹€. μ΄ˆκΈ°κ°’μ€ Max이닀.

while(Min <= Max)
{
    int EstimateScore = (Min + Max) / 2;
    if(IsValid(EstimateScore))
    {
        Score = min(Score, EstimateScore);
        Max = EstimateScore - 1;
    }
    else
    {
        Min = EstimateScore + 1;
    }
}

μ „ν˜•μ μΈ 이진탐색 λ‘œμ§μ΄λ‹€. IsValid() ν•¨μˆ˜μ˜ κ²°κ³Όκ°€ true이면 쑰건에 λΆ€ν•©ν•œ μΆ”μ • 점수라 이λ₯Ό minimum update μˆ˜ν–‰ν•œλ‹€.

auto IsValid = [&](int EstimateScore)
{
    int Count = 1;
    int Min = Nums[0], Max = Nums[0];
    
    for(int i = 1; i < N; ++i)
    {
        Min = min(Min, Nums[i]);
        Max = max(Max, Nums[i]);
        
        if(Max - Min > EstimateScore)
        {
            Count++;
            Min = Nums[i];
            Max = Nums[i];
        }
    }
    
    return Count <= M;
};

핡심 λ‘œμ§μ΄λ‹€. 예λ₯Ό λ“€μ–΄λ³΄μž: [1, 5, 4, 6, 2, 1, 3, 7], M = 3

  • EstimateScore == 3: ꡬ간은 [1, 5], [4, 6], [2, 1, 3], [7]둜 4개둜 M보닀 크기 λ•Œλ¬Έμ— 적정 μΆ”μ • μ μˆ˜κ°€ μ•„λ‹ˆλ‹€. / Min = 4(κ°±μ‹ ), Max = 7
  • EstimateScore == 5: ꡬ간은 [1, 5, 4, 6, 2, 1, 3], [7]둜 2κ°œμ΄λ―€λ‘œ 적정 μΆ”μ • μ μˆ˜μ΄λ‹€. -> min(Score, EstimateScore) = min(7, 5): 5 κ°±μ‹  / Min = 4, Max = 4(κ°±μ‹ )
  • EstimateScore == 4: ꡬ간은 [1, 5, 4], [6, 2], [1, 3], [7]둜 4κ°œμ΄λ―€λ‘œ 적정 μΆ”μ • μ μˆ˜κ°€ μ•„λ‹ˆλ‹€. / Min = 5, Max = 4
  • Min > Maxμ΄λ―€λ‘œ break

λ”°λΌμ„œ 정닡은 5이닀.

전체 μ½”λ“œ

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    
    int N, M; cin >> N >> M;
    
    vector<int> Nums(N);
    for(int& Num : Nums)
    {
        cin >> Num;
    }
    
    auto IsValid = [&](int EstimateScore)
    {
        int Count = 1;
        int Min = Nums[0], Max = Nums[0];
        
        for(int i = 1; i < N; ++i)
        {
            Min = min(Min, Nums[i]);
            Max = max(Max, Nums[i]);
            
            if(Max - Min > EstimateScore)
            {
                Count++;
                Min = Nums[i];
                Max = Nums[i];
            }
        }
        
        return Count <= M;
    };
    
    int Min = 0, Max = *max_element(Nums.begin(), Nums.end());
    int Score = Max;
    while(Min <= Max)
    {
        int EstimateScore = (Min + Max) / 2;
        if(IsValid(EstimateScore))
        {
            Score = min(Score, EstimateScore);
            Max = EstimateScore - 1;
        }
        else
        {
            Min = EstimateScore + 1;
        }
    }
    
    cout << Score;

    return 0;
}

πŸ“š μƒˆλ‘­κ²Œ μ•Œκ²Œλœ λ‚΄μš©

이 λ¬Έμ œλŠ” 2024 NHN κ²Œμž„ 곡채 μ½”λ”© ν…ŒμŠ€νŠΈ λ¬Έμ œμ™€ μœ μ‚¬ν•˜λ‹€(λ””μŠ€μ½”λ“œμ— κ΄€λ ¨ ν¬μŠ€νŠΈκ°€ μžˆμœΌλ‹ˆ λ§Žκ΄€λΆ€!).

μ½”ν…Œ μΉ  λ‹Ήμ‹œμ—λŠ” μ–΄λ–€ μœ ν˜•μΈμ§€ νŒŒμ•…ν•˜μ§€ λͺ»ν•΄ λͺ» ν’€μ—ˆλŠ”λ° @mjj111 λ‹˜μ΄ "이거 μ΄μ§„νƒμƒ‰μž„!" ν•΄μ„œ λˆˆμ— λΆˆμ„ ν‚€κ³  λ°±μ€€ λ’€μ Έλ³΄λ‹ˆ λΉ„μŠ·ν•œ 게 이 λ¬Έμ œμ˜€λ‹€.

트라이 ν•΄λ΄€μ§€λ§Œ... 1μ‹œκ°„ λ™μ•ˆ 감도 λͺ»μž‘κ³  레퍼런슀 ν™•μΈν•˜κ³  λ‚˜μ„œμ•Ό 겨우겨우 끄적일 수 μžˆμ—ˆλ˜...

ν•œλ™μ•ˆ λ°±νŠΈλž˜ν‚Ή/이진탐색/그리디/DP μœ„μ£Όλ‘œ ν’€μ–΄μ•Όκ² λ‹€.

p.s. 참고둜 이 λ¬Έμ œλŠ” N의 크기가 μž‘μ–΄μ„œ λ‹€μŒκ³Ό 같이 μ„ ν˜• 탐색을 해도 ν†΅κ³Όν•œλ‹€.

int Score = 10001;
for(int EstimateScore = 0; EstimateScore < *max_element(Nums.begin(), Nums.end()); ++EstimateScore)
{
    if(IsValid(EstimateScore))
    {
        Score = min(Score, EstimateScore);
    }
}

image
(μœ„κ°€ μ„ ν˜•νƒμƒ‰, μ•„λž˜κ°€ 이진탐색)

Copy link
Collaborator

@mjj111 mjj111 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μ§„μ§œ 이 문제λ₯Ό μ™œ... κ·Έ NHN μ‹œν—˜ λ•ŒλŠ” μ–΄λ²„λ²„λŒ”λŠ”μ§€.. ν™”κ°€ λ‚˜λŠ”κ΅°μš”..

n, m = map(int, input().split())
numbers = list(map(int, input().split()))
start = 0
end = max(numbers) - min(numbers)

def can_do(target):
    m_count = 1 
    min_value = numbers[0]
    max_value = numbers[0]
    
    for number in numbers[1:]:
        min_value = min(min_value, number)
        max_value = max(max_value, number)
        
        if max_value - min_value > target:
            m_count += 1  
            min_value = number 
            max_value = number
            
            if m_count > m:
                return False
    return True

while start <= end:
    mid = (start + end) // 2
    if can_do(mid):
        end = mid - 1
    else:
        start = mid + 1

print(start)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants