※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 10164번 문제인 격자상의 경로이다.
문제는 아래 링크를 확인하자.

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

 

10164번: 격자상의 경로

입력의 첫째 줄에는 격자의 행의 수와 열의 수를 나타내는 두 정수 N과 M(1 ≤ N, M ≤ 15), 그리고 ○로 표시된 칸의 번호를 나타내는 정수 K(K=0 또는 1 < K < N×M)가 차례로 주어지며, 각 값은 공백으

www.acmicpc.net

격자 위에서 경로의 개수는 조합을 이용하여 간단히 계산 가능하다.

동그라미로 나타나는 칸의 행과 열을 사칙연산을 이용하여 계산해낼 수 있다면 문제를 쉽게 해결할 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
using namespace std;

int comb[32][32];

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	for (int i = 0; i < 32; i++) {
		comb[i][0] = comb[i][i] = 1;
	}

	for (int r = 2; r < 32; r++) {
		for (int c = 1; c < r; c++) {
			comb[r][c] = comb[r - 1][c - 1] + comb[r - 1][c];
		}
	}

	int R, C, K; cin >> R >> C >> K;
	if (K == 0) {
		cout << comb[R + C - 2][C - 1];
	}
	else {
		int r = (K - 1) / C + 1, c = (K - 1) % C + 1;
		cout << comb[r + c - 2][c - 1] * comb[R - r + C - c][C - c];
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 10972 // C++] 다음 순열  (0) 2021.07.29
[BOJ 10973 // C++] 이전 순열  (0) 2021.07.28
[BOJ 10651 // C++] Cow Jog  (0) 2021.07.26
[BOJ 14003 // C++] 가장 긴 증가하는 부분 수열 5  (0) 2021.07.25
[BOJ 2568 // C++] 전깃줄 - 2  (0) 2021.07.24

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 10651번 문제인 Cow Jog이다.
문제는 아래 링크를 확인하자.

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

 

10651번: Cow Jog

Farmer John's N cows (1 <= N <= 100,000) are out exercising their hooves again, jogging along an infinite track.  Each cow starts at a distinct position on the track, and some cows run at different speeds. The track is divided into lanes so that cows may

www.acmicpc.net

L을 소가 달리기 시작하는 위치, R을 소가 달리기를 마치는 위치를 의미하는 알파벳으로 사용하겠다.

 

시간 T동안 소 A가 L1에서 R1까지, 소 B가 L2에서 R2까지 뛰었다고 해보자. (단, L1<L2)

그렇다면, R1<R2이면 두 소는 충돌하지 않고 뛸 것이고, 그렇지 않다면 충돌할 것이라는 것을 알 수 있다.

한편, 문제에서 구하는 lane 수는 어떤 두마리 소를 골라도 달리는 중에 충돌하게 되는 집합의 최대 크기를 구하는 문제로 생각할 수 있다. 이는, (서로 다른) L이 정렬되어 입력이 들어올 때 R값들의 순서를 역순으로 살펴서 찾을 수 있는 LIS의 길이와 같다는 것을 알 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;

vector<pair<ll, int>> arr;

bool xcomp(pair<ll, int> p1, pair<ll, int> p2) {
	if (p1.first != p2.first) return p1.first < p2.first;
	return p1.second > p2.second;
}

bool icomp(pair<ll, int> p1, pair<ll, int> p2) {
	return p1.second < p2.second;
}

int seg[262145];

int update(int L, int R, int qI, int qVal, int sI) {
	if (R < qI || qI < L) return seg[sI];
	if (L == R) return seg[sI] = qVal;
	return seg[sI] = max(update(L, (L + R) / 2, qI, qVal, sI * 2), update((L + R) / 2 + 1, R, qI, qVal, sI * 2 + 1));
}

int rangemax(int L, int R, int qL, int qR, int sI) {
	if (R < qL || qR < L) return 0;
	if (qL <= L && R <= qR) return seg[sI];
	return max(rangemax(L, (L + R) / 2, qL, qR, sI * 2), rangemax((L + R) / 2 + 1, R, qL, qR, sI * 2 + 1));
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	int N; ll T; cin >> N >> T;
	
	for (int i = 0; i < N; i++) {
		ll x, v; cin >> x >> v;
		arr.push_back({ x + v * T,i });
	}

	sort(arr.begin(), arr.end(), xcomp);
	
	for (int i = 0; i < N; i++) {
		arr[i].first = i + 1;
	}

	sort(arr.begin(), arr.end(), icomp);

	int cnt = 0;
	for (auto iter = arr.rbegin(); iter != arr.rend(); iter++) {
		int temp = rangemax(1, N, 1, (*iter).first, 1) + 1;
		if (temp > cnt) cnt = temp;
		update(1, N, (*iter).first, temp, 1);
	}

	cout << cnt;
}
728x90

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 14003번 문제인 가장 긴 증가하는 부분 수열 5이다.
문제는 아래 링크를 확인하자.

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

 

14003번: 가장 긴 증가하는 부분 수열 5

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (-1,000,000,000 ≤ Ai ≤ 1,000,000,000)

www.acmicpc.net

크기 100만의 수열이 주어질 때, LIS중 하나를 찾아 출력해주면 된다.

LIS중 하나를 역추적하기 위하여 글쓴이는 수를 입력받을 때마다 그 수로 끝나는 가장 긴 증가하는 부분수열의 이전 수가 무엇인지를 기록해두었다. 그리고, LIS를 이루는 마지막 수를 찾아 위의 기록해둔 배열을 이용하여 LIS를 역추적하였다.

 

(세그먼트트리로 LIS 구하기 연습2)

 

아래는 제출한 소스코드이다.

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

vector<pair<int, int>> arr;
int seg[2097153];

int nth(int L, int R, int n) {
    int sI = 1;
    while (L < R) {
        if (seg[sI * 2] < n) {
            L = (L + R) / 2 + 1;
            sI = sI * 2 + 1;
        }
        else {
            R = (L + R) / 2;
            sI = sI * 2;
        }
    }
    return L;
}

int update(int L, int R, int qI, int qVal, int sI) {
    if (R < qI || qI < L) return seg[sI];
    if (L == R) return seg[sI] = qVal;
    return seg[sI] = max(update(L, (L + R) / 2, qI, qVal, sI * 2), update((L + R) / 2 + 1, R, qI, qVal, sI * 2 + 1));
}

int rangemax(int L, int R, int qL, int qR, int sI) {
    if (R < qL || qR < L) return 0;
    if (qL <= L && R <= qR) return seg[sI];
    return max(rangemax(L, (L + R) / 2, qL, qR, sI * 2), rangemax((L + R) / 2 + 1, R, qL, qR, sI * 2 + 1));
}

int inv[1000001];
int val[1000001];
int parent[1000000];
bool xcomp(pair<int, int> p1, pair<int, int> p2) {
    if (p1.first != p2.first) return p1.first < p2.first;
    return p1.second > p2.second;
}

bool icomp(pair<int, int> p1, pair<int, int> p2) {
    return p1.second < p2.second;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int N; cin >> N;
    for (int i = 0; i < N; i++) {
        int x; cin >> x;
        arr.push_back({ x,i });
    }

    sort(arr.begin(), arr.end(), xcomp);

    for (int i = 1; i <= N; i++) {
        val[i] = arr[i - 1].first;
        arr[i - 1].first = i;
    }

    sort(arr.begin(), arr.end(), icomp);

    int cnt = 0, last;
    for (int i = 0; i < N; i++) {
        int x = arr[i].first;
        int temp = rangemax(1, N, 1, x, 1);
        parent[x] = nth(1, N, temp);
        temp++;
        if (temp > cnt) {
            cnt = temp;
            last = x;
        }
        update(1, N, x, temp, 1);
    }

    cout << cnt << '\n';

    vector<int> stk;
    while (cnt--) {
        stk.push_back(last);
        last = parent[last];
    }

    while (!stk.empty()) {
        cout << val[stk.back()] << ' ';
        stk.pop_back();
    }
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 10164 // C++] 격자상의 경로  (0) 2021.07.27
[BOJ 10651 // C++] Cow Jog  (0) 2021.07.26
[BOJ 2568 // C++] 전깃줄 - 2  (0) 2021.07.24
[BOJ 18263 // C++] Milk Visits  (0) 2021.07.23
[BOJ 13913 // C++] 숨바꼭질 4  (0) 2021.07.22

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 2568번 문제인 전깃줄 - 2이다.
문제는 아래 링크를 확인하자.

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

 

2568번: 전깃줄 - 2

첫째 줄에는 두 전봇대 사이의 전깃줄의 개수가 주어진다. 전깃줄의 개수는 100,000 이하의 자연수이다. 둘째 줄부터 한 줄에 하나씩 전깃줄이 A전봇대와 연결되는 위치의 번호와 B전봇대와 연결

www.acmicpc.net

최소한의 전깃줄을 지워 전깃줄이 교차하는 부분을 없앤다는 것은 최대한의 교차하지 않는 전깃줄을 남긴다는 말과 같다. 최대한의 교차하지 않는 전깃줄의 개수는 LIS를 구하는 것과 같다는 것을 알 수 있을 것이다.

따라서, LIS의 크기를 구하고 LIS를 역추적하여 아무거나 하나를 구한 다음 그 전선들을 제외한 나머지 전선들을 없애는 것으로 문제를 해결할 수 있다.

 

(세그먼트트리로 LIS 구하기 연습1)

 

아래는 제출한 소스코드이다.

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

int parent[500001];
vector<pair<int,int>> arr;
int seg[1048577];

int update(int L, int R, int qI, int qVal, int sI) {
    if (R < qI || qI < L) return seg[sI];
    if (L == R) return seg[sI] = qVal;
    return seg[sI] = max(update(L, (L + R) / 2, qI, qVal, sI * 2), update((L + R) / 2 + 1, R, qI, qVal, sI * 2 + 1));
}

int nth(int L, int R, int N) {
    int sI = 1;
    while (L < R) {
        if (seg[sI * 2] < N) {
            sI = sI * 2 + 1;
            L = (L + R) / 2 + 1;
        }
        else {
            sI = sI * 2;
            R = (L + R) / 2;
        }
    }
    return L;
}

int rangemax(int L, int R, int qL, int qR, int sI) {
    if (qR < L || R < qL) return 0;
    if (qL <= L && R <= qR) return seg[sI];
    return max(rangemax(L, (L + R) / 2, qL, qR, sI * 2), rangemax((L + R) / 2 + 1, R, qL, qR, sI * 2 + 1));
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int N; cin >> N;
    for (int i = 0; i < N; i++) {
        int x, y; cin >> x >> y;
        arr.push_back({ x,y });
    }

    sort(arr.begin(), arr.end());

    int ans = 0;
    int last;
    for (auto node : arr) {
        int x = node.second;
        int temp = rangemax(1, 500000, 1, x, 1);
        parent[x] = nth(1, 500000, temp);
        temp++;
        if (temp > ans) {
            last = x;
            ans = temp;
        }
        update(1, 500000, x, temp, 1);
    }

    for (int i = 0; i < ans; i++) {
        int l = parent[last];
        parent[last] = 9999999;
        last = l;
    }

    cout << N - ans << '\n';
    for (int i = 0; i < N; i++) {
        if (parent[arr[i].second] < 999999) cout << arr[i].first << '\n';
    }
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 10651 // C++] Cow Jog  (0) 2021.07.26
[BOJ 14003 // C++] 가장 긴 증가하는 부분 수열 5  (0) 2021.07.25
[BOJ 18263 // C++] Milk Visits  (0) 2021.07.23
[BOJ 13913 // C++] 숨바꼭질 4  (0) 2021.07.22
[BOJ 1647 // C++] 도시 분할 계획  (0) 2021.07.21

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 18263번 문제인 Milk Visits이다.
문제는 아래 링크를 확인하자.

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

 

18263번: Milk Visits

Farmer John is planning to build $N$ ($1 \leq N \leq 10^5$) farms that will be connected by $N-1$ roads, forming a tree (i.e., all farms are reachable from each-other, and there are no cycles). Each farm contains a cow with an integer type $T_i$ between $1

www.acmicpc.net

HLD(Heavy-Light Decomposition)로 트리를 분해해두고, 구간합 세그먼트 트리(segment tree)와 오프라인 쿼리(offline query) 테크닉으로 각 소의 타입별로 가중치를 부여했다 지웠다 하는 것으로 문제를 해결할 수 있다.

구체적으로, 두 노드를 잇는 경로 사이의 노드의 가중치를 모두 합했을 때 양수이면 1, 그렇지 않으면 0으로 생각할 수 있다.

 

아래는 제출한 소스코드이다.

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

vector<int> G[100001];

int heavychild[100001];
int dfs(int current, int parent) {
    int childcnt = 1;
    int hchild = -1;
    int hcount = -1;
    for (auto node : G[current]) {
        if (node == parent) continue;
        int temp = dfs(node, current);
        childcnt += temp;
        if (temp > hcount) {
            hcount = temp, hchild = node;
        }
    }
    heavychild[current] = hchild;
    return childcnt;
}

int nodeidx[100001];
int chainidx[100001];
int cparent[100001];
int cnth[100001];
int cdepth[100001];
int nidx = 1, cidx = 1;
void hld(int current, int parent, int cp, int cn, int cd) {
    nodeidx[current] = nidx;
    chainidx[nidx] = cidx;
    cparent[nidx] = cp;
    cnth[nidx] = cn;
    cdepth[nidx] = cd;

    int hchild = heavychild[current];
    if (hchild > 0) {
        nidx++;
        hld(hchild, current, cp, cn + 1, cd);
    }
    cd++;
    for (auto node : G[current]) {
        if (node == parent || node == hchild) continue;
        nidx++; cidx++;
        hld(node, current, nodeidx[current], 0, cd);
    }
}

vector<int> cowtype[100001];

struct query {
    int idx;
    int x, y, c;
    int ans;
};

bool qccomp(query q1, query q2) {
    return q1.c < q2.c;
}

bool qicomp(query q1, query q2) {
    return q1.idx < q2.idx;
}

vector<query> queries;

int seg[262145];

void update(int L, int R, int qI, int qVal) {
    int sI = 1;
    while (L < R) {
        seg[sI] += qVal;
        int mid = (L + R) / 2;
        if (qI <= mid) {
            R = mid;
            sI = sI * 2;
        }
        else {
            L = mid + 1;
            sI = sI * 2 + 1;
        }
    }
    seg[sI] += qVal;
}

int rangesum(int L, int R, int qL, int qR, int sI) {
    if (R < qL || qR < L) return 0;
    if (qL <= L && R <= qR) return seg[sI];
    return rangesum(L, (L + R) / 2, qL, qR, sI * 2) + rangesum((L + R) / 2 + 1, R, qL, qR, sI * 2 + 1);
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int N, M; cin >> N >> M;
    for (int i = 1; i <= N; i++) {
        int x; cin >> x;
        cowtype[x].push_back(i);
    }

    for (int i = 1; i < N; i++) {
        int x, y; cin >> x >> y;
        G[x].push_back(y);
        G[y].push_back(x);
    }

    dfs(1, 0);
    hld(1, 0, 0, 0, 0);
    
    for (int i = 1;i <= M;i++) {
        int x, y, c; cin >> x >> y >> c;
        query temp; temp.idx = i, temp.x = x, temp.y = y, temp.c = c;
        queries.push_back(temp);
    }

    sort(queries.begin(), queries.end(), qccomp);

    int oldc = 0;
    for (int i = 0; i < M; i++) {
        query q = queries[i];
        if (q.c != oldc) {
            for (auto c : cowtype[oldc]) update(1, N, nodeidx[c], -1);
            for (auto c : cowtype[q.c]) update(1, N, nodeidx[c], 1);
            oldc = q.c;
        }
        
        int x = nodeidx[q.x], y = nodeidx[q.y];

        int temp = 0;

        if (cdepth[x] != cdepth[y]) {
            if (cdepth[x] < cdepth[y]) swap(x, y);
            while (cdepth[x] > cdepth[y]) {
                temp += rangesum(1, N, x - cnth[x], x, 1);
                x = cparent[x];
            }
        }

        while (chainidx[x] != chainidx[y]) {
            temp += rangesum(1, N, x - cnth[x], x, 1) + rangesum(1, N, y - cnth[y], y, 1);
            x = cparent[x], y = cparent[y];
        }

        if (x > y) swap(x, y);
        temp += rangesum(1, N, x, y, 1);

        if (temp > 0) queries[i].ans = 1;
        else queries[i].ans = 0;
    }

    sort(queries.begin(), queries.end(), qicomp);
    
    for (auto q : queries) {
        cout << q.ans;
    }
}
728x90

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 13913번 문제인 숨바꼭질 4이다.
문제는 아래 링크를 확인하자.

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

 

13913번: 숨바꼭질 4

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일

www.acmicpc.net

각 숫자 N에 대하여, N+1, N-1과 2*N을 향한 (방향이 있는) 에지가 있는 방향그래프를 생각해보자.

이 그래프에서, 수빈이가 있는 점을 출발점으로, 동생이 있는 점을 도착점으로 하는 BFS를 하면 문제를 해결할 수 있다.

 

실제 방문순서는 이 점을 오기 전에 어떤 점에서 왔는지를 기록해두는 것(BFS트리의 부모를 기록해두는 것)으로 다시 역추적할 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <stack>
#include <queue>
using namespace std;

int dist[200001];
int parent[200001];
queue<int> que;
stack<int> stk;

int cnt = 0;

void bfs() {
	while (!que.empty()) {
		int current = que.front();
		if (current > 0) {
			if (dist[current - 1] == 0) {
				dist[current - 1] = dist[current] + 1;
				parent[current - 1] = current;
				que.push(current - 1);
			}
		}
		if (current < 200000) {
			if (dist[current + 1] == 0) {
				dist[current + 1] = dist[current] + 1;
				parent[current + 1] = current;
				que.push(current + 1);
			}
		}
		if (current * 2 <= 200000) {
			if (dist[current * 2] == 0) {
				dist[current * 2] = dist[current] + 1;
				parent[current * 2] = current;
				que.push(current * 2);
			}
		}
		que.pop();
	}
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	int S, E; cin >> S >> E;
	dist[S] = 1;
	parent[S] = S;
	que.push(S);
	bfs();

	cout << dist[E] - 1 << '\n';
	
	while (E != S) {
		stk.push(E);
		E = parent[E];
	}

	cout << S << ' ';
	while (!stk.empty()) {
		cout << stk.top() << ' ';
		stk.pop();
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 2568 // C++] 전깃줄 - 2  (0) 2021.07.24
[BOJ 18263 // C++] Milk Visits  (0) 2021.07.23
[BOJ 1647 // C++] 도시 분할 계획  (0) 2021.07.21
[BOJ 15480 // C++] LCA와 쿼리  (0) 2021.07.20
[BOJ 3351 // C++] 삼각 분할  (0) 2021.07.19

+ Recent posts