2017년 11월 27일 월요일

5000 빵 정렬

5000 빵 정렬 https://www.acmicpc.net/problem/5000

1부터 N까지의 빵 번호가 주어진다.
세개의 빵을 한번에 뒤집을 수 있는데 가장 오른쪽에 있는 빵이 맨 왼쪽, 나머지는 오른쪽으로 한칸씩 밀려진다.
빵 순서를 사장이 원하는 순서로 바꿀 수 있는지 판단하는 문제다.

정답률이 85%정도 되는데 쉬운문제는 아니다.
직접 손으로 경우를 그려보니 사장이 원하는 순서의 첫번째 숫자부터 맞추면서 판단하면 해결이 가능해보였다.

두 가지 경우로 나뉘었다.
사장이 원하는 순서의 맨 앞에빵이 6번이다.
상근이의 6번빵은 5번째 index에 위치하는데 위와같이 6번빵을 당길 수 있다.
이때 사장과 상근이의 빵의 위치의 차이가 홀수인 경우에는 앞에 두 빵을 swap해서 저장해야한다.
짝수인 경우에는 swap할 필요없이 그대로 저장하면 된다.

여기까지는 생각해내는데 금방이였는데 자료구조를 어떻게 구현해야할지 한참걸렸다.
좀 복잡하지만 segment tree를 이용해 구현해냈다.
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace    std;
int N;
int src[100001];
int dst[100001];
int pos[100001];
struct Segment {
    vector<int> tree;
    int size;
    Segment() {}
    Segment(int N) :size(N) { tree.resize(4*N, 0); }
    int update(int idx, int val, int nl, int nr, int node) {
        if (idx < nl || idx > nr) return tree[node];
        if (nl == nr) return tree[node] += val;
        int mid = (nl + nr) >> 1;
        return tree[node] = update(idx, val, nl, mid, node * 2+ update(idx, val, mid + 1, nr, node * 2 + 1);
    }
    void update(int idx, int val) {
        update(idx, val, 0size - 11);
    }
    int query(int l, int r, int nl, int nr, int node) {
        if (r < nl || l > nr) return 0;
        if (l <= nl && nr <= r) return tree[node];
        int mid = (nl + nr) >> 1;
        return query(l, r, nl, mid, node * 2+ query(l, r, mid + 1, nr, node * 2 + 1);
    }
    int query(int l, int r) {
        return query(l, r, 0size - 11);
    }
    int find(int val, int node, int nl, int nr) {
        if (nl == nr) return  nl;
        int mid = (nl + nr) >> 1;
        if (tree[node * 2>= val) return find(val, node*2, nl, mid);
        else return find(val - tree[node * 2], node * 2 + 1, mid + 1, nr);
    }
    int find(int val) {
        return find(val, 10size - 1);
    }
};
int main() {
    scanf("%d"&N);
    Segment seg(N + 1);
    for (int n = 0;n < N;n++scanf("%d"&src[n]), pos[src[n]] = n, seg.update(n, 1);
    for (int n = 0;n < N;n++) {
        scanf("%d"&dst[n]);
        if (n >= N - 2continue;
        int idx = seg.query(0, pos[dst[n]]) - 1;
        seg.update(pos[dst[n]], -1);
        if ((idx) % 2 == 1) {
            int g1 = seg.find(1), g2 = seg.find(2);
            swap(pos[src[g1]], pos[src[g2]]);
            swap(src[g1], src[g2]);
        }
    }
    if (src[seg.find(1)] == dst[N - 2&& src[seg.find(2)] == dst[N - 1]) printf("Possible\n");
    else printf("Impossible\n");
    return 0;
}
cs
다른 분들은 BIT, fenwick tree를 이용해서 짧게 푸셨는데 코드 해석을 못하겠다.

댓글 없음:

댓글 쓰기