27313번: 효율적인 애니메이션 감상

첫 번째 줄에 한별이가 봐야 하는 애니메이션의 개수 $N$, 한별이가 애니메이션을 보는 데에 사용할 수 있는 시간을 나타내는 정수 $M$, 한별이가 동시에 볼 수 있는 애니메이션의 개수 $K$가 공백

www.acmicpc.net

이분탐색 문제입니다.

 

이 문제에 이분탐색을 어떻게 적용할 수 있을까 엄청 고민했는데, 

일단 정렬하고 생각해봤습니다.

 

애니메이션을 보는데 걸리는 시간은 보는 애니 중 가장 길이가 긴 것입니다.

따라서 가장 긴 것만 본다고 가정합니다.

 

또한, 애니메이션은 항상 k개씩 봐야지 가장 많이 볼 수 있습니다.

따라서 k는 고정입니다.

 

그럼 애니메이션을 몇 개 볼 수 있는지에 대해서 이분탐색을 할 수 있습니다.

7 10 2
2 3 1 4 5 6 7

위와 같이 입력이 들어올 경우

1 2 3 4 5 6 7로 정렬될 겁니다.

이분탐색에서 시작은 1, 끝은 7일 것이며, 중간은 4가 됩니다. 

애니를 4편 봤지만 걸린 총 시간은 6으로, 이는 m값인 10보다 작습니다.

시작점을 중간으로 옮겨주면

시작은 4, 끝은 7, 중간은 5가 됩니다.

애니 5편을 봤을 때 총 걸린 시간은 9로, 이는 m값인 10보다 작습니다.

시작점을 5로, 이에 중간을  6으로 옮기면 총 시간은 12로, m보다 큽니다.

이렇게 이분탐색을 진행하면 0번째부터 시작점까지의 영화를 모두 볼 수 있습니다.

 

사이드케이스로,

1 1 1
10

과 같은 입력이 들어올 경우, 0번째의 원소 하나만으로도 m값을 넘기기에 이를 신경써야합니다.

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
long long arr[100000],n,m,k,tmp,ans = -1,fir,e,mid, coun;
int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin>>n>>m>>k;
    for(int i = 0; i < n; i++) cin>>arr[i];
    sort(arr, arr + n);
    
    fir = 0;
    e = n;
    for(int i = 0; i < log2(n); i++) {
        tmp = coun = 0;
        mid = (fir + e) / 2;
        for(int j = mid; j >= 0; j -= k) {
            coun++;
            tmp += arr[j];
        }
        if(tmp <= m) {
            ans = max(ans, coun);
            fir = mid;
        }
        else {
            e = mid;
        }
    }
    
    if(arr[fir] > m) cout<<0; //가장 짧은 애니도 m보다 길 경우
    else cout<<fir + 1;
}

 

 

 

 

1018번: 체스판 다시 칠하기

첫째 줄에 N과 M이 주어진다. N과 M은 8보다 크거나 같고, 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에는 보드의 각 행의 상태가 주어진다. B는 검은색이며, W는 흰색이다.

www.acmicpc.net

 

1. N x M 크기의 배열에서 8 x 8 만큼만 잘라내는 법

2. 8 x 8 크기의 배열에서 흰색과 검정색을 교차로 설정하는 법

위의 2가지를 알면 쉽게 구현할 수 있는 브루트포스 문제입니다.

 

입력이 주어지면 위의 그림만큼 8 x 8만큼 씩만 탐색을 해야하며,

그 내부에서 교차로 선택하는 방법을 알아야 합니다.

 

    for(int i = 0; i <= n - 8; i++) {
        for(int j = 0; j <= m - 8; j++) {

~~~

~~~

        }

    }

 

이 부분이 배열에서 8 x 8 만큼씩 탐색하는 방법이고

그 밑의 조건문은 흰색과 검정색을 교차로 놓는 부분입니다.

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
string s[50];

int main() {
    int n,m;
    cin>>n>>m;
    for(int i = 0; i < n; i++) {
        cin>>s[i];
    }
    int coun, coun2, ans = 100;
    for(int i = 0; i <= n - 8; i++) {
        for(int j = 0; j <= m - 8; j++) { //1번 부분
            coun2 = coun = 0;
            for(int k = 0; k < 8; k++) {
                for(int l = 0; l < 8; l++) {
                    if((k + i) % 2 == 0 && (l + j) % 2 == 0 && s[k + i][l + j] == 'B') coun++; //2번 부분
                    if((k + i) % 2 == 1 && (l + j) % 2 == 1 && s[k + i][l + j] == 'B') coun++;
                    if((k + i) % 2 == 1 && (l + j) % 2 == 0 && s[k + i][l + j] == 'W') coun++;
                    if((k + i) % 2 == 0 && (l + j) % 2 == 1 && s[k + i][l + j] == 'W') coun++;

                    if((k + i) % 2 == 0 && (l + j) % 2 == 0 && s[k + i][l + j] == 'W') coun2++;
                    if((k + i) % 2 == 1 && (l + j) % 2 == 1 && s[k + i][l + j] == 'W') coun2++;
                    if((k + i) % 2 == 1 && (l + j) % 2 == 0 && s[k + i][l + j] == 'B') coun2++;
                    if((k + i) % 2 == 0 && (l + j) % 2 == 1 && s[k + i][l + j] == 'B') coun2++; 
                }
            }
            ans = min({ans, coun, coun2});
        }
    }
    cout<<ans;
}
 

19590번: 비드맨

구슬을 엄청 좋아하는 비드맨이 있다. 구슬만 보면 갖고 싶어 하는 비드맨은 오늘도 갖고 싶은 구슬을 발견했다. 그러나 비드맨은 현재 구슬을 너무 많이 갖고 있기 때문에 더 이상 구슬을 가질

www.acmicpc.net

재밌는 그리디 문제이다.

 

종류가 다른 구슬을 2개씩 부딪혀 깰 수 있다고 할 때, 

최소한의 구슬을 남기는 문제다.

 

 

25635번: 자유 이용권

자유 이용권은 놀이공원의 모든 놀이기구를 횟수의 제한 없이 마음껏 이용할 수 있는 이용권이다. 준원이는 ANA 놀이공원의 자유 이용권을 구매했고, 최대한 많이 놀이기구를 이용할 생각이다.

www.acmicpc.net

비슷한 문제로 자유 이용권 문제가 있다.

 

풀이 방법은,

가장 많은 개수의 구슬을 n, 나머지 총합을 m으로 뒀을 때

1. n > m 이라면 무조건 n - m 의 구슬은 남고, 나머지는 깰 수 있다.

2. n = m 이라면 0개의 구슬만 남는다.

3. n < m 이라면 전체 구슬이 홀수라면 1개가, 아니라면 0개가 남는다.

 

따라서 아래와 같이 작성할 수 있다.

#include <iostream>
#include <algorithm>
using namespace std;
long long n, m,k,arr[100001];
int main() {
    ios::sync_with_stdio(0);cin.tie(0);
    cin>>k;
    
    for(int i = 0; i < k; i++) cin>>arr[i];
    sort(arr, arr + k);
    
    n = arr[k - 1]; //최댓값
    for(int i = 0; i < k - 1; i++) {
        m += arr[i]; //나머지
    }
    if(n > m) cout<< n - m;
    else {
        if((n + m) % 2) cout<<1;
        else cout<<0;
    }
}

추가적으로

 

27311번: 치노의 라떼 아트 (Easy)

각 테스트 케이스에 대해, 주어진 라떼 아트가 하트 모양이면 1, 아니면 0을 한 줄에 하나씩 출력한다.

www.acmicpc.net

이 문제를 풀지 못해서 너무 스트레스 받는다..

실버 2의 마인크래프트를 어떻게 푸는지 모를 때의 기분과 같다.

 

17143번: 낚시왕

낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다.

www.acmicpc.net

문제에 적힌 순서대로 구현했다.

 

1. 낚시왕을 옮기고, 같은 열의 상어를 잡는다.

2. 상어를 옮기고, 그 상어의 위치를 임시로 저장한다. 나는 arr에 저장했다.

3. 옮긴 상어의 위치에 다른 상어가 있다면, 큰 상어만 남긴다.

4. 이동이 끝나면 arr에 임시로 저장돼있는 상어를 전부 map에 다시 옮겨준다.

 

위의 과정을 낚시왕이 1열에서 c열까지 이동할 때까지

즉, c번 반복하며 최종 점수를 출력하면 된다.

 

상어의 최대 속력은 1000으로, 나와 같이 while 문으로 모든 상어를 천 번씩 옮기면 TLE를 받는다.

따라서 모듈러 연산을 통해 양 벽을 부딪힌 후,

상어가 같은 방향, 같은 위치로 돌아올 경우에서부터 계산을 해주면 된다.

 

구현 문제인데, 문제가 친절하고 자세하게 설명돼있어 골드 1 문제같지는 않았다.

큰 상어만 남기는 아이디어가 힘들긴 했다.

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Shark {
    int R, C, speed, dir, sco;
};
vector<Shark> map[101][101];
vector<Shark> arr[101][101];
int dx[5] = {0, -1, 1, 1, -1}, score;

int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int r,c,m;
    cin>>r>>c>>m;
    for(int i = 0; i < m; i++) {
        struct Shark a;
        cin>>a.R>>a.C>>a.speed>>a.dir>>a.sco;
        if(a.dir == 1 || a.dir == 2) a.speed %= (r - 1) * 2;
        else a.speed %= (c - 1) * 2;
        map[a.R][a.C].push_back(a);
    }
    
    int fisher = 0, coun = c;
    while(coun--) {
        fisher++; //낚시왕 옮기기
        for(int i = 1; i <= r; i++) { //상어 잡기
            if(map[i][fisher].empty()) continue;
            score += map[i][fisher][0].sco;
            map[i][fisher].pop_back();
            break;
        }
        
        for(int i = 1; i <= r; i++) { //상어가 있다면 옮겨주기
            for(int j = 1; j <= c; j++) {
                if(map[i][j].empty()) continue;
                struct Shark t = map[i][j][0];
                int move = t.speed;
                if(t.dir == 1 || t.dir == 2) {
                    while(move--) {
                        if(t.R == 1) t.dir = 2;
                        if(t.R == r) t.dir = 1;
                        t.R += dx[t.dir];
                    }
                }
                else {
                    while(move--) {
                        if(t.C == 1) t.dir = 3;
                        if(t.C == c) t.dir = 4;
                        t.C += dx[t.dir];
                    }
                }
                
                if(arr[t.R][t.C].empty()) {//큰 상어만 남기기
                    arr[t.R][t.C].push_back(t);
                }
                else {
                    if(arr[t.R][t.C][0].sco < t.sco) {
                        arr[t.R][t.C].pop_back();
                        arr[t.R][t.C].push_back(t);
                    }
                }
            }
        }
        
        for(int i = 1; i <= r; i++) { //업데이트
            for(int j = 1; j <= c; j++) {
                map[i][j] = arr[i][j];
                if(!arr[i][j].empty()) arr[i][j].pop_back();
            }
        }
    }
    cout<<score;
}

+ Recent posts