728x90
반응형
  • 문제

보석 공장에서 보석 상자를 유치원에 기증했다. 각각의 보석은 M가지 서로 다른 색상 중 한 색상이다. 원장 선생님은 모든 보석을 N명의 학생들에게 나누어 주려고 한다. 이때, 보석을 받지 못하는 학생이 있어도 된다. 하지만, 학생은 항상 같은 색상의 보석만 가져간다.

한 아이가 너무 많은 보석을 가져가게 되면, 다른 아이들이 질투를 한다. 원장 선생님은 이런 질투심을 수치화하는데 성공했는데, 질투심은 가장 많은 보석을 가져간 학생이 가지고 있는 보석의 개수이다. 원장 선생님은 질투심이 최소가 되게 보석을 나누어 주려고 한다.

상자에 빨간 보석이 4개 (RRRR), 파란 보석이 7개 (BBBBBBB) 있었고, 이 보석을 5명의 아이들에게 나누어 주는 경우를 생각해보자. RR, RR, BB, BB, BBB로 보석을 나누어주면 질투심은 3이 되고, 이 값보다 작게 나누어 줄 수 없다.

상자 안의 보석 정보와 학생의 수가 주어졌을 때, 질투심이 최소가 되게 보석을 나누어주는 방법을 알아내는 프로그램을 작성하시오.

  • 입력

첫째 줄에 아이들의 수 N과 색상의 수 M이 주어진다. (1 ≤ N ≤ 10^9, 1 ≤ M ≤ 300,000, M ≤ N)

다음 M개 줄에는 구간 [1, 10^9]에 포함되는 양의 정수가 하나씩 주어진다. K번째 줄에 주어지는 숫자는 K번 색상 보석의 개수이다.

  • 출력

첫째 줄에 질투심의 최솟값을 출력한다.

  • 예제 입력
5 2
7
4
7 5
7
1
7
4
4
  • 예제 출력
3
4
  • 접근방식

질투심이 x일 때, 충족이 되는지만 구하면 된다. 즉, 이분 탐색으로 풀 수 있다.

  • 코드
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int n, m;
long long a[300004], low = 1, high = 0, mid, result = 99999999;

bool check(long long mid)
{
    long long num = 0;
    for (int i = 0; i < m; i++)
    {
        num += a[i] / mid;
        if (a[i] % mid)
        {
            num++;
        }
    }
    return n >= num;
}

int main()
{
    cin >> n >> m;

    for (int i = 0; i < m; i++)
    {
        cin >> a[i];
        high = max(high, a[i]);
    }

    while (low <= high)
    {
        mid = (low + high) / 2;
        if (check(mid))
        {
            result = min(result, mid);
            high = mid - 1;
        }
        else
        {
            low = mid + 1;
        }
    }

    cout << result;

    return 0;
}
 

2792번: 보석 상자

보석 공장에서 보석 상자를 유치원에 기증했다. 각각의 보석은 M가지 서로 다른 색상 중 한 색상이다. 원장 선생님은 모든 보석을 N명의 학생들에게 나누어 주려고 한다. 이때, 보석을 받지 못하

www.acmicpc.net

 

728x90
반응형

'C++ > BOJ' 카테고리의 다른 글

[C++]/백준 2343번 기타 레슨  (1) 2024.03.28
[C++]/백준 2170번 선 긋기  (0) 2024.03.26
[C++]/백준 17822번 원판 돌리기  (0) 2024.03.26
[C++]/백준 15683번 감시  (0) 2024.03.26
[C++]/백준 1912번 연속합  (0) 2024.03.26
728x90
반응형
  • 문제

매우 큰 도화지에 자를 대고 선을 그으려고 한다. 선을 그을 때에는 자의 한 점에서 다른 한 점까지 긋게 된다. 선을 그을 때에는 이미 선이 있는 위치에 겹쳐서 그릴 수도 있는데, 여러 번 그은 곳과 한 번 그은 곳의 차이를 구별할 수 없다고 하자.

이와 같은 식으로 선을 그었을 때, 그려진 선(들)의 총 길이를 구하는 프로그램을 작성하시오. 선이 여러 번 그려진 곳은 한 번씩만 계산한다.

  • 입력

첫째 줄에 선을 그은 횟수 N (1 ≤ N ≤ 1,000,000)이 주어진다. 다음 N개의 줄에는 선을 그을 때 선택한 두 점의 위치 x, y (-1,000,000,000 ≤ x < y ≤ 1,000,000,000)가 주어진다.

  • 출력

첫째 줄에 그은 선의 총 길이를 출력한다.

  • 예제 입력
4
1 3
2 5
3 5
6 7
  • 예제 출력
5
  • 접근방식

그냥 단순하게 카운팅 배열로 하려고 했지만 범위가 10억이여서 라인 스위핑으로 해결했다.

범위에서 겹쳐지면 오른쪽 부분만 갱신하고 겹쳐지지 않으면 오른쪽 부분 - 왼쪽 부분을 더하고 둘 다 갱신 시켜준다.

  • 코드
#include <iostream>
#include <algorithm>

using namespace std;

int n, _left, _right, from, to, result;
pair<int, int> Line[1000004];

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    cin >> n;

    for (int i = 0; i < n; i++)
    {
        cin >> from >> to;
        Line[i] = { from,to };
    }

    sort(Line, Line + n);

    _left = Line[0].first;
    _right = Line[0].second;

    for (int i = 1; i < n; i++)
    {
        if (_right < Line[i].first) // 겹쳐지지 않으면
        {
            result += (_right - _left);
            _left = Line[i].first;
            _right = Line[i].second;
        }
        else if (Line[i].first <= _right && Line[i].second >= _right) // 겹쳐지면 갱신
        {
            _right = Line[i].second;
        }
    }

    result += _right - _left;
    cout << result;

    return 0;
}
 

2170번: 선 긋기

첫째 줄에 선을 그은 횟수 N (1 ≤ N ≤ 1,000,000)이 주어진다. 다음 N개의 줄에는 선을 그을 때 선택한 두 점의 위치 x, y (-1,000,000,000 ≤ x < y ≤ 1,000,000,000)가 주어진다.

www.acmicpc.net

 

728x90
반응형

'C++ > BOJ' 카테고리의 다른 글

[C++]/백준 2343번 기타 레슨  (1) 2024.03.28
[C++]/백준 2792번 보석상자  (1) 2024.03.27
[C++]/백준 17822번 원판 돌리기  (0) 2024.03.26
[C++]/백준 15683번 감시  (0) 2024.03.26
[C++]/백준 1912번 연속합  (0) 2024.03.26
728x90
반응형
  • 문제

반지름이 1, 2, ..., N인 원판이 크기가 작아지는 순으로 바닥에 놓여있고, 원판의 중심은 모두 같다. 원판의 반지름이 i이면, 그 원판을 i번째 원판이라고 한다. 각각의 원판에는 M개의 정수가 적혀있고, i번째 원판에 적힌 j번째 수의 위치는 (i, j)로 표현한다. 수의 위치는 다음을 만족한다.

  • (i, 1)은 (i, 2), (i, M)과 인접하다.
  • (i, M)은 (i, M-1), (i, 1)과 인접하다.
  • (i, j)는 (i, j-1), (i, j+1)과 인접하다. (2 ≤ j ≤ M-1)
  • (1, j)는 (2, j)와 인접하다.
  • (N, j)는 (N-1, j)와 인접하다.
  • (i, j)는 (i-1, j), (i+1, j)와 인접하다. (2 ≤ i ≤ N-1)

아래 그림은 N = 3, M = 4인 경우이다.

원판의 회전은 독립적으로 이루어진다. 2번 원판을 회전했을 때, 나머지 원판은 회전하지 않는다. 원판을 회전시킬 때는 수의 위치를 기준으로 하며, 회전시킨 후의 수의 위치는 회전시키기 전과 일치해야 한다.

다음 그림은 원판을 회전시킨 예시이다.

 

원판을 아래와 같은 방법으로 총 T번 회전시키려고 한다. 원판의 회전 방법은 미리 정해져 있고, i번째 회전할때 사용하는 변수는 xi, di, ki이다.

  1. 번호가 xi의 배수인 원판을 di방향으로 ki칸 회전시킨다. di가 0인 경우는 시계 방향, 1인 경우는 반시계 방향이다.
  2. 원판에 수가 남아 있으면, 인접하면서 수가 같은 것을 모두 찾는다.
    1. 그러한 수가 있는 경우에는 원판에서 인접하면서 같은 수를 모두 지운다.
    2. 없는 경우에는 원판에 적힌 수의 평균을 구하고, 평균보다 큰 수에서 1을 빼고, 작은 수에는 1을 더한다.

원판을 T번 회전시킨 후 원판에 적힌 수의 합을 구해보자.

  • 입력

첫째 줄에 N, M, T이 주어진다.

둘째 줄부터 N개의 줄에 원판에 적힌 수가 주어진다. i번째 줄의 j번째 수는 (i, j)에 적힌 수를 의미한다.

다음 T개의 줄에 xi, di, ki가 주어진다.

  • 출력

원판을 T번 회전시킨 후 원판에 적힌 수의 합을 출력한다.

  • 예제 입력
4 4 1
1 1 2 3
5 2 4 2
3 1 3 5
2 1 3 2
2 0 1
4 4 2
1 1 2 3
5 2 4 2
3 1 3 5
2 1 3 2
2 0 1
3 1 3
4 4 3
1 1 2 3
5 2 4 2
3 1 3 5
2 1 3 2
2 0 1
3 1 3
2 0 2
4 4 4
1 1 2 3
5 2 4 2
3 1 3 5
2 1 3 2
2 0 1
3 1 3
2 0 2
3 1 1
4 6 3
1 2 3 4 5 6
2 3 4 5 6 7
3 4 5 6 7 8
4 5 6 7 8 9
2 1 4
3 0 1
2 1 2
  • 예제 출력
30
22
22
0
26
  • 접근방식

원판을 x배수 만큼 돌리고 인접한 수는 0으로 만들고 나머지 숫자들만 더하고 평균을 냈다.

원판을 돌릴때는 rotate함수를 사용하였다.

  • 코드
#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>

using namespace std;

const int dy[] = { -1,0,1,0 };
const int dx[] = { 0,1,0,-1 };

int n, m, t, x, d, k, circle[54][54], visited[54][54], result;
bool flag = 1;

void _rotate(int y, int direction, int k)
{
    vector<int> v;
    for (int i = 0; i < m; i++)
    {
        v.push_back(circle[y][i]);
    }

    if (direction == 1)
    {
        rotate(v.begin(), v.begin() + k, v.end());
    }
    else
    {
        rotate(v.begin(), v.begin() + m - k, v.end());
    }
    
    for (int i = 0; i < m; i++)
    {
        circle[y][i] = v[i];
    }
    return;
}

void dfs(int y, int x)
{
    for (int i = 0; i < 4; i++)
    {
        int ny = y + dy[i];
        int nx = (x + dx[i] + m) % m;

        if (ny < 0 || ny >= n || visited[ny][nx])  continue;
        if (circle[y][x] == circle[ny][nx])
        {
            visited[y][x] = visited[ny][nx] = 1;
            flag = 0;
            dfs(ny, nx);
        }
    }
}

bool findAdj()
{
    flag = 1;

    memset(visited, 0, sizeof(visited));

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (circle[i][j] == 0 || visited[i][j])   continue;
            dfs(i, j);
        }
    }

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (visited[i][j])
            {
                circle[i][j] = 0;
            }
        }
    }
    return flag;
}

void setAverage()
{
    int sum = 0;
    int cnt = 0;

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (circle[i][j] == 0)   continue;
            sum += circle[i][j];
            cnt++;
        }
    }

    double average = (double)sum / (double)cnt;

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (circle[i][j] == 0)   continue;
            if ((double)circle[i][j] > average)
            {
                circle[i][j]--;
            }
            else if ((double)circle[i][j] < average)
            {
                circle[i][j]++;
            }
        }
    }
    return;
}

int main()
{
    cin >> n >> m >> t;

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> circle[i][j];
        }
    }

    for (int i = 0; i < t; i++)
    {
        cin >> x >> d >> k;

        for (int j = x - 1; j < n; j += x)
        {
            _rotate(j, d, k);
        }

        if (findAdj())
        {
            setAverage();
        }
    }

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            result += circle[i][j];
        }
    }
    
    cout << result;

    return 0;
}
 

17822번: 원판 돌리기

반지름이 1, 2, ..., N인 원판이 크기가 작아지는 순으로 바닥에 놓여있고, 원판의 중심은 모두 같다. 원판의 반지름이 i이면, 그 원판을 i번째 원판이라고 한다. 각각의 원판에는 M개의 정수가 적혀

www.acmicpc.net

 

728x90
반응형

'C++ > BOJ' 카테고리의 다른 글

[C++]/백준 2792번 보석상자  (1) 2024.03.27
[C++]/백준 2170번 선 긋기  (0) 2024.03.26
[C++]/백준 15683번 감시  (0) 2024.03.26
[C++]/백준 1912번 연속합  (0) 2024.03.26
[C++]/백준 2632번 피자판매  (0) 2024.03.26
728x90
반응형
  • 문제

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감시할 수 있는 방법은 다음과 같다.

1번 CCTV는 한 쪽 방향만 감시할 수 있다. 2번과 3번은 두 방향을 감시할 수 있는데, 2번은 감시하는 방향이 서로 반대방향이어야 하고, 3번은 직각 방향이어야 한다. 4번은 세 방향, 5번은 네 방향을 감시할 수 있다.

CCTV는 감시할 수 있는 방향에 있는 칸 전체를 감시할 수 있다. 사무실에는 벽이 있는데, CCTV는 벽을 통과할 수 없다. CCTV가 감시할 수 없는 영역은 사각지대라고 한다.

CCTV는 회전시킬 수 있는데, 회전은 항상 90도 방향으로 해야 하며, 감시하려고 하는 방향이 가로 또는 세로 방향이어야 한다.

0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 6 0
0 0 0 0 0 0

지도에서 0은 빈 칸, 6은 벽, 1~5는 CCTV의 번호이다. 위의 예시에서 1번의 방향에 따라 감시할 수 있는 영역을 '#'로 나타내면 아래와 같다.

CCTV는 벽을 통과할 수 없기 때문에, 1번이 → 방향을 감시하고 있을 때는 6의 오른쪽에 있는 칸을 감시할 수 없다.

0 0 0 0 0 0
0 2 0 0 0 0
0 0 0 0 6 0
0 6 0 0 2 0
0 0 0 0 0 0
0 0 0 0 0 5

위의 예시에서 감시할 수 있는 방향을 알아보면 아래와 같다.

CCTV는 CCTV를 통과할 수 있다. 아래 예시를 보자.

0 0 2 0 3
0 6 0 0 0
0 0 6 6 0
0 0 0 0 0

위와 같은 경우에 2의 방향이 ↕ 3의 방향이 ←와 ↓인 경우 감시받는 영역은 다음과 같다.

# # 2 # 3
0 6 # 0 #
0 0 6 6 #
0 0 0 0 #

사무실의 크기와 상태, 그리고 CCTV의 정보가 주어졌을 때, CCTV의 방향을 적절히 정해서, 사각 지대의 최소 크기를 구하는 프로그램을 작성하시오.

  • 입력

첫째 줄에 사무실의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 8)

둘째 줄부터 N개의 줄에는 사무실 각 칸의 정보가 주어진다. 0은 빈 칸, 6은 벽, 1~5는 CCTV를 나타내고, 문제에서 설명한 CCTV의 종류이다. 

CCTV의 최대 개수는 8개를 넘지 않는다.

  • 출력

첫째 줄에 사각 지대의 최소 크기를 출력한다.

  • 예제 입력
4 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 6 0
0 0 0 0 0 0
6 6
0 0 0 0 0 0
0 2 0 0 0 0
0 0 0 0 6 0
0 6 0 0 2 0
0 0 0 0 0 0
0 0 0 0 0 5
6 6
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
6 6
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 5 0 0
0 0 5 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
1 7
0 1 2 3 4 5 6
3 7
4 0 0 0 0 0 0
0 0 0 2 0 0 0
0 0 0 0 0 0 4
  • 예제 출력
20
15
6
2
0
0
  • 접근방식

CCTV마다 탐색 범위를 다르게 설정해서 해당 좌표들을 변경한다음에
dfs를 통해 사각지대를 더한다.

방향을 돌려가면서 경우의 수를 찾을때 %4(4방향)을 사용한다.

  • 코드
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

const int dy[] = { -1,0,1,0 };
const int dx[] = { 0,1,0,-1 };

int n, m, _map[10][10], temp[10][10], result = 99999999;
vector<pair<int, int>> v;

bool CheckOver(int ny, int nx)
{
    if (ny < n && ny >= 0 && nx < m && nx >= 0 && _map[ny][nx] != 6)
    {
        return true;
    }
    return false;
}

vector<pair<int, int>> extendCCTV(int here, int direction)
{
    vector<pair<int, int>> _change;
    int y = v[here].first;
    int x = v[here].second;
    
    if (_map[y][x] == 1) // 1방향 카메라
    {
        while (1)
        {
            int ny = y + dy[direction];
            int nx = x + dx[direction];

            if (CheckOver(ny,nx))
            {
                if (_map[ny][nx] == 0)
                {
                    _map[ny][nx] = '#';
                    _change.push_back({ ny,nx });
                }
                y = ny;
                x = nx;
            }
            else
            {
                break;
            }
        }
    }
    else if (_map[y][x] == 2) // 2방향 앞뒤 카메라
    {
        for (int i = 0; i <= 2; i += 2)
        {
            int _y = y;
            int _x = x;

            while (1)
            {
                int ny = _y + dy[(direction + i) % 4];
                int nx = _x + dx[(direction + i) % 4];

                if (CheckOver(ny, nx))
                {
                    if (_map[ny][nx] == 0)
                    {
                        _map[ny][nx] = '#';
                        _change.push_back({ ny,nx });
                    }
                    _y = ny;
                    _x = nx;
                }
                else
                {
                    break;
                }
            }
        }
    }
    else if (_map[y][x] == 3) // 2방향  직각 카메라
    {
        for (int i = 0; i < 2; i++)
        {
            int _y = y;
            int _x = x;

            while (1)
            {
                int ny = _y + dy[(direction + i) % 4];
                int nx = _x + dx[(direction + i) % 4];

                if (CheckOver(ny, nx))
                {
                    if (_map[ny][nx] == 0)
                    {
                        _map[ny][nx] = '#';
                        _change.push_back({ ny,nx });
                    }
                    _y = ny;
                    _x = nx;
                }
                else
                {
                    break;
                }
            }
        }
    }
    else if (_map[y][x] == 4) // 3방향 카메라
    {
        for (int i = 0; i < 3; i++)
        {
            int _y = y;
            int _x = x;

            while (1)
            {
                int ny = _y + dy[(direction + i) % 4];
                int nx = _x + dx[(direction + i) % 4];

                if (CheckOver(ny, nx))
                {
                    if (_map[ny][nx] == 0)
                    {
                        _map[ny][nx] = '#';
                        _change.push_back({ ny,nx });
                    }
                    _y = ny;
                    _x = nx;
                }
                else
                {
                    break;
                }
            }
        }
    }
    else if (_map[y][x] == 5) // 4방향 카메라
    {
        for (int i = 0; i < 4; i++)
        {
            int _y = y;
            int _x = x;

            while (1)
            {
                int ny = _y + dy[(direction + i) % 4];
                int nx = _x + dx[(direction + i) % 4];

                if (CheckOver(ny, nx))
                {
                    if (_map[ny][nx] == 0)
                    {
                        _map[ny][nx] = '#';
                        _change.push_back({ ny,nx });
                    }
                    _y = ny;
                    _x = nx;
                }
                else
                {
                    break;
                }
            }
        }
    }
    return _change;
}

void dfs(int here)
{
    if (here == v.size())
    {
        int cnt = 0;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                if (_map[i][j] == 0)
                {
                    cnt++;
                }
            }
        }
        result = min(cnt, result);
        return;
    }
    for (int i = 0; i < 4; i++)
    {
        vector<pair<int, int>> _change = extendCCTV(here, i);
        dfs(here + 1);
        for (auto b : _change)
        {
            _map[b.first][b.second] = 0;
        }
    }
}

int main()
{
    cin >> n >> m;

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> _map[i][j];
            if (_map[i][j] != 6 && _map[i][j] != 0)
            {
                v.push_back({ i,j });
            }
        }
    }

    dfs(0);
    cout << result;

    return 0;
}
 

15683번: 감시

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감

www.acmicpc.net

 

728x90
반응형

'C++ > BOJ' 카테고리의 다른 글

[C++]/백준 2170번 선 긋기  (0) 2024.03.26
[C++]/백준 17822번 원판 돌리기  (0) 2024.03.26
[C++]/백준 1912번 연속합  (0) 2024.03.26
[C++]/백준 2632번 피자판매  (0) 2024.03.26
[C++]/백준 17143번 낚시왕  (0) 2024.03.26
728x90
반응형
  • 문제

n개의 정수로 이루어진 임의의 수열이 주어진다. 우리는 이 중 연속된 몇 개의 수를 선택해서 구할 수 있는 합 중 가장 큰 합을 구하려고 한다. 단, 수는 한 개 이상 선택해야 한다.

예를 들어서 10, -4, 3, 1, 5, 6, -35, 12, 21, -1 이라는 수열이 주어졌다고 하자. 여기서 정답은 12+21인 33이 정답이 된다.

  • 입력

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

  • 출력

첫째 줄에 답을 출력한다.

  • 예제 입력
10
10 -4 3 1 5 6 -35 12 21 -1
10
2 1 -4 3 4 -4 6 5 -5 1
5
-1 -2 -3 -4 -5
  • 예제 출력
33
14
-1
  • 접근방식

구간을 더하면서 더한 수(sum)가 음수면은 더한 수(sum)을 버리고 계속 이어 나간다.

  • 코드
#include <iostream>
#include <algorithm>

using namespace std;

int n, sum, a, result = -1001;

int main()
{
    cin >> n;

    for (int i = 0; i < n; i++)
    {
        cin >> a;
        sum += a;
        result = max(result, sum);
        if (sum < 0)
        {
            sum = 0;
        }
    }

    cout << result;

    return 0;
}
 

1912번: 연속합

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

www.acmicpc.net

 

728x90
반응형

'C++ > BOJ' 카테고리의 다른 글

[C++]/백준 17822번 원판 돌리기  (0) 2024.03.26
[C++]/백준 15683번 감시  (0) 2024.03.26
[C++]/백준 2632번 피자판매  (0) 2024.03.26
[C++]/백준 17143번 낚시왕  (0) 2024.03.26
[C++]/백준 14888번 연산자 끼워넣기  (1) 2024.03.25
728x90
반응형
  • 문제

고객이 두 종류의 피자 A와 B를 취급하는 피자가게에서 피자를 주문하고자 한다. <그림 1>과 같이 각 종류의 피자는 다양한 크기의 여러 개의 피자조각으로 나누어져 있다. 각 조각에 쓰여진 숫자는 피자조각의 크기를 나타낸다.

고객이 원하는 피자의 크기를 이야기하면, 피자가게에서는 한 종류의 피자를 2 조각 이상 판매할 때는 반드시 연속된 조각들을 잘라서 판매한다. 이때 판매한 피자조각의 크기 합이 주문한 크기가 되어야 한다. 판매한 피자조각은 모두 A종류이거나, 모두 B종류이거나, 또는 A와 B 종류가 혼합될 수 있다. 예를 들어서, <그림 1> 과 같이 잘라진 피자가 있을 때, 손님이 전체 크기가 7 인 피자를 주문하면, 피자 가게에서는 <그림2>와 같이 5 가지 방법으로 피자를 판매할 수 있다.

 

피자가게에서 손님이 원하는 크기의 피자를 판매하는 모든 방법의 가지 수를 계산하는 프로그램을 작성하시오

  • 입력

첫 번째 줄에는 손님이 구매하고자 하는 피자크기를 나타내는 2,000,000 이하의 자연수가 주어진다. 두 번째 줄에는 A, B 피자의 피자조각의 개수를 나타내 는 정수 m, n 이 차례로 주어진다 (3 ≤ m, n ≤ 1000). 세 번째 줄부터 차례로 m 개의 줄에는 피자 A의 미리 잘라진 피자조각의 크기를 나타내는 정수가 주어진다. 그 다음 n 개의 줄에는 차례로 피자B의 미리 잘라진 피자조각의 크기를 나타내는 정수가 주어진다. 각 종류의 피자조각의 크기는 시계방향으로 차례로 주어지며, 각 피자 조각의 크기는 1000 이하의 자연수이다.

  • 출력

첫째 줄에는 피자를 판매하는 방법의 가지 수를 나타내는 정수를 출력한다. 피자를 판매하는 방법이 없는 경우에는 숫자 0을 출력한다.

  • 예제 입력
7
5 3
2
2
1
7
2
6
8
3
  • 예제 출력
5
  • 접근방식

누적합을 이용해서 푸는데
a에서 만들수 있는 경우의 수, b에서 만들수 있는 경우의 수, a와 b에서 꺼내서 만들수 있는 경우의 수를 더하면 된다.

  • 코드
#include <iostream>
#include <algorithm>
#include <map>

using namespace std;

int wantSize, n, m, a[1004], b[1004], psum_a[2008], psum_b[2008], result;
map<int, int> cnt_a, cnt_b;

void make(int n, int psum[], map<int, int>& cnt)
{
    for (int i = 1; i <= n; i++)
    {
        for (int j = i; j <= n + i - 1; j++)
        {
            int sum = psum[j] - psum[j - i];
            cnt[sum]++;
            if (i == n)  break;
        }
    }
    return;
}

int main()
{

    cin >> wantSize >> n >> m;

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

    for (int i = n + 1; i <= 2 * n; i++)
    {
        psum_a[i] = psum_a[i - 1] + a[i - n];
    }

    for (int i = 1; i <= m; i++)
    {
        cin >> b[i];
        psum_b[i] = psum_b[i - 1] + b[i];
    }

    for (int i = m + 1; i <= 2 * m; i++)
    {
        psum_b[i] = psum_b[i - 1] + b[i - m];
    }

    make(n, psum_a, cnt_a);
    make(m, psum_b, cnt_b);

    for (int i = 1; i < wantSize; i++)
    {
        result += cnt_a[wantSize - i] * cnt_b[i];
    }

    result += cnt_a[wantSize];
    result += cnt_b[wantSize];

    cout << result;

    return 0;
}
 

2632번: 피자판매

첫 번째 줄에는 손님이 구매하고자 하는 피자크기를 나타내는 2,000,000 이하의 자연수가 주어진다. 두 번째 줄에는 A, B 피자의 피자조각의 개수를 나타내 는 정수 m, n 이 차례로 주어진다 (3 ≤ m, n

www.acmicpc.net

 

728x90
반응형

'C++ > BOJ' 카테고리의 다른 글

[C++]/백준 15683번 감시  (0) 2024.03.26
[C++]/백준 1912번 연속합  (0) 2024.03.26
[C++]/백준 17143번 낚시왕  (0) 2024.03.26
[C++]/백준 14888번 연산자 끼워넣기  (1) 2024.03.25
[C++]/백준 1911번 흙길 보수하기  (0) 2024.03.25
728x90
반응형
  • 문제

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

낚시왕은 처음에 1번 열의 한 칸 왼쪽에 있다. 다음은 1초 동안 일어나는 일이며, 아래 적힌 순서대로 일어난다. 낚시왕은 가장 오른쪽 열의 오른쪽 칸에 이동하면 이동을 멈춘다.

  1. 낚시왕이 오른쪽으로 한 칸 이동한다.
  2. 낚시왕이 있는 열에 있는 상어 중에서 땅과 제일 가까운 상어를 잡는다. 상어를 잡으면 격자판에서 잡은 상어가 사라진다.
  3. 상어가 이동한다.

상어는 입력으로 주어진 속도로 이동하고, 속도의 단위는 칸/초이다. 상어가 이동하려고 하는 칸이 격자판의 경계를 넘는 경우에는 방향을 반대로 바꿔서 속력을 유지한채로 이동한다.

왼쪽 그림의 상태에서 1초가 지나면 오른쪽 상태가 된다. 상어가 보고 있는 방향이 속도의 방향, 왼쪽 아래에 적힌 정수는 속력이다. 왼쪽 위에 상어를 구분하기 위해 문자를 적었다.

상어가 이동을 마친 후에 한 칸에 상어가 두 마리 이상 있을 수 있다. 이때는 크기가 가장 큰 상어가 나머지 상어를 모두 잡아먹는다.

낚시왕이 상어 낚시를 하는 격자판의 상태가 주어졌을 때, 낚시왕이 잡은 상어 크기의 합을 구해보자.

  • 입력

첫째 줄에 격자판의 크기 R, C와 상어의 수 M이 주어진다. (2 ≤ R, C ≤ 100, 0 ≤ M ≤ R×C)

둘째 줄부터 M개의 줄에 상어의 정보가 주어진다. 상어의 정보는 다섯 정수 r, c, s, d, z (1 ≤ r ≤ R, 1 ≤ c ≤ C, 0 ≤ s ≤ 1000, 1 ≤ d ≤ 4, 1 ≤ z ≤ 10000) 로 이루어져 있다. (r, c)는 상어의 위치, s는 속력, d는 이동 방향, z는 크기이다. d가 1인 경우는 위, 2인 경우는 아래, 3인 경우는 오른쪽, 4인 경우는 왼쪽을 의미한다.

두 상어가 같은 크기를 갖는 경우는 없고, 하나의 칸에 둘 이상의 상어가 있는 경우는 없다.

  • 출력

낚시왕이 잡은 상어 크기의 합을 출력한다.

  • 예제 입력
4 6 8
4 1 3 3 8
1 3 5 2 9
2 4 8 4 1
4 5 0 1 4
3 3 1 2 7
1 5 8 4 3
3 6 2 1 2
2 2 2 3 5
100 100 0
4 5 4
4 1 3 3 8
1 3 5 2 9
2 4 8 4 1
4 5 0 1 4
2 2 4
1 1 1 1 1
2 2 2 2 2
1 2 1 2 3
2 1 2 1 4
  • 예제 출력
22
0
22
4
  • 접근방식

1. 사람이 움직이면서 상어를 잡는 처리
2. 상어가 움직이면서 상어를 먹는 처리
3. 벽에 부딪히면 방향 전환

방향이 1부터 시작하므로 {0,0,0,1,-1} 같이 크기가 5인 dx dy 필요
좌표도 1부터 시작하므로 1부터 시작하거나 -1을 하여 0으로 맞춰줘야함
temp를 통해서 상어가 계속 이동하는 것을 구현해서 현재 맵에 다시 덮어주기

  • 코드
#include <iostream>
#include <algorithm>
#include <string.h>

using namespace std;

struct Shark
{
    int x, y, s, z, dir, death;
}a[104 * 104];

const int dx[] = { 0, 0, 0, 1, -1 };
const int dy[] = { 0, -1, 1, 0, 0 };

int R, C, M, result, _map[104][104], temp[104][104];

int main()
{
    cin >> R >> C >> M;

    for (int i = 1; i <= M; i++)
    {
        cin >> a[i].y >> a[i].x >> a[i].s >> a[i].dir >> a[i].z;
        a[i].y -= 1;
        a[i].x -= 1;
        _map[a[i].y][a[i].x] = i;
    }

    for (int t = 0; t < C; t++)
    {
        for (int y = 0; y < R; y++) // 이동하면서 상어 잡는 처리
        {
            if (_map[y][t])
            {
                a[_map[y][t]].death = 1;
                result += a[_map[y][t]].z;
                _map[y][t] = 0;
                break;
            }
        }

        memset(temp, 0, sizeof(temp));

        for (int i = 1; i <= M; i++) // 상어가 움직이는 처리
        {
            if (a[i].death) continue;

            int _y = a[i].y;
            int _x = a[i].x;
            int s = a[i].s;
            int d = a[i].dir;
            int ny, nx;

            while (1) // 벽에 부딪히면 방향 전환
            {
                ny = _y + s * dy[d];
                nx = _x + s * dx[d];
                if (nx < C && ny < R && ny >= 0 && nx >= 0) break;
                if (d == 1 && ny < 0)
                {
                    s -= _y;
                    _y = 0;
                    d = 2;
                }
                else if (d == 2 && ny >= R)
                {
                    s -= R - 1 - _y;
                    _y = R - 1;
                    d = 1;
                }
                else if (d == 3 && nx >= C)
                {
                    s -= C - 1 - _x;
                    _x = C - 1;
                    d = 4;
                }
                else if (d == 4 && nx < 0)
                {
                    s -= _x;
                    _x = 0;
                    d = 3;
                }
            }
            if (temp[ny][nx])
            {
                if (a[temp[ny][nx]].z < a[i].z)
                { 
                    a[temp[ny][nx]].death = 1;
                    temp[ny][nx] = i;
                }
                else
                {
                    a[i].death = 1;
                }
            }
            else
            {
                temp[ny][nx] = i;
            }

            a[i].x = nx;
            a[i].y = ny;
            a[i].dir = d;
        }

        memcpy(_map, temp, sizeof(temp));

    }

    cout << result;

    return 0;
}
 

17143번: 낚시왕

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

www.acmicpc.net

 

728x90
반응형

'C++ > BOJ' 카테고리의 다른 글

[C++]/백준 1912번 연속합  (0) 2024.03.26
[C++]/백준 2632번 피자판매  (0) 2024.03.26
[C++]/백준 14888번 연산자 끼워넣기  (1) 2024.03.25
[C++]/백준 1911번 흙길 보수하기  (0) 2024.03.25
[C++]/백준 15662번 톱니바퀴 (2)  (0) 2024.03.25
728x90
반응형
  • 문제

N개의 수로 이루어진 수열 A1, A2, ..., AN이 주어진다. 또, 수와 수 사이에 끼워넣을 수 있는 N-1개의 연산자가 주어진다. 연산자는 덧셈(+), 뺄셈(-), 곱셈(×), 나눗셈(÷)으로만 이루어져 있다.

우리는 수와 수 사이에 연산자를 하나씩 넣어서, 수식을 하나 만들 수 있다. 이때, 주어진 수의 순서를 바꾸면 안 된다.

예를 들어, 6개의 수로 이루어진 수열이 1, 2, 3, 4, 5, 6이고, 주어진 연산자가 덧셈(+) 2개, 뺄셈(-) 1개, 곱셈(×) 1개, 나눗셈(÷) 1개인 경우에는 총 60가지의 식을 만들 수 있다. 예를 들어, 아래와 같은 식을 만들 수 있다.

  • 1+2+3-4×5÷6
  • 1÷2+3+4-5×6
  • 1+2÷3×4-5+6
  • 1÷2×3-4+5+6

식의 계산은 연산자 우선 순위를 무시하고 앞에서부터 진행해야 한다. 또, 나눗셈은 정수 나눗셈으로 몫만 취한다. 음수를 양수로 나눌 때는 C++14의 기준을 따른다. 즉, 양수로 바꾼 뒤 몫을 취하고, 그 몫을 음수로 바꾼 것과 같다. 이에 따라서, 위의 식 4개의 결과를 계산해보면 아래와 같다.

  • 1+2+3-4×5÷6 = 1
  • 1÷2+3+4-5×6 = 12
  • 1+2÷3×4-5+6 = 5
  • 1÷2×3-4+5+6 = 7

N개의 수와 N-1개의 연산자가 주어졌을 때, 만들 수 있는 식의 결과가 최대인 것과 최소인 것을 구하는 프로그램을 작성하시오.

  • 입력

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 곱셈(×)의 개수, 나눗셈(÷)의 개수이다.

  • 출력

첫째 줄에 만들 수 있는 식의 결과의 최댓값을, 둘째 줄에는 최솟값을 출력한다. 연산자를 어떻게 끼워넣어도 항상 -10억보다 크거나 같고, 10억보다 작거나 같은 결과가 나오는 입력만 주어진다. 또한, 앞에서부터 계산했을 때, 중간에 계산되는 식의 결과도 항상 -10억보다 크거나 같고, 10억보다 작거나 같다.

  • 예제 입력
2
5 6
0 0 1 0
3
3 4 5
1 0 1 0
6
1 2 3 4 5 6
2 1 1 1
  • 예제 출력
30
30
35
17
54
-24
  • 접근방식

연산자의 갯수를 하나씩 줄여가면서 연산자의 수가 모두 떨어질 때 까지 계산하면 된다.

  • 코드
#include <iostream>
#include <algorithm>

using namespace std;

int n, a[12], b[4], p, minu, mult, divi, max_result = -1000000001, min_result = 1000000001;

void calculate(int idx, int cur, int plus, int minus, int mul, int div)
{
	if (idx == n - 1)
	{
		max_result = max(cur, max_result);
		min_result = min(min_result, cur);
		return;
	}
	if (plus)	calculate(idx + 1, cur + a[idx + 1], plus - 1, minus, mul, div);
	if (minus)	calculate(idx + 1, cur - a[idx + 1], plus, minus - 1, mul, div);
	if (mul)	 calculate(idx + 1, cur * a[idx + 1], plus, minus, mul - 1, div);
	if (div) calculate(idx + 1, cur / a[idx + 1], plus, minus, mul, div - 1);
	return;
}

int main()
{
	cin >> n;

	for (int i = 0; i < n; i++)
	{
		cin >> a[i];
	}

	cin >> p >> minu >> mult >> divi;

	calculate(0, a[0], p, minu, mult, divi);

	cout << max_result << endl << min_result;

    return 0;
}
 

14888번: 연산자 끼워넣기

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 곱

www.acmicpc.net

 

728x90
반응형

'C++ > BOJ' 카테고리의 다른 글

[C++]/백준 2632번 피자판매  (0) 2024.03.26
[C++]/백준 17143번 낚시왕  (0) 2024.03.26
[C++]/백준 1911번 흙길 보수하기  (0) 2024.03.25
[C++]/백준 15662번 톱니바퀴 (2)  (0) 2024.03.25
[C++]/백준 17406번 배열 돌리기 4  (0) 2024.03.25

+ Recent posts