페이지

레이블이 link인 게시물을 표시합니다. 모든 게시물 표시
레이블이 link인 게시물을 표시합니다. 모든 게시물 표시

3392번: 화성 지도

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


$O(n\lg L)$

plane sweeping
http://codedoc.tistory.com/421

#include<cstdio>
#include<algorithm>
using namespace std;
const int MXN = 1e4, MXL = 3e4;
int n, lt[MXL * 4], ct[MXL * 4], res;
struct st {
    int x, y1, y2, s;
}l[MXN * 2];
void update(int h, int l, int r, int gl, int gr, int s) {
    if (r < gl || gr < l) return;
    if (gl <= l && r <= gr) ct[h] += s;
    else {
        update(h * 2 + 1, l, (l + r) / 2, gl, gr, s);
        update(h * 2 + 2, (l + r) / 2 + 1, r, gl, gr, s);
    }
    lt[h] = !ct[h] ? l^r ? lt[h * 2 + 1] + lt[h * 2 + 2] : 0 : r - l + 1;
}
int main() {
    scanf("%d", &n);
    for (int i = 0, x1, y1, x2, y2; i < n; i++) {
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        l[i] = { x1,y1,y2 - 1,1 };
        l[i + n] = { x2,y1,y2 - 1,-1 };
    }
    sort(l, l + 2 * n, [](st i, st j) {return i.x < j.x; });
    for (int i = 0; i < 2 * n; i++) {
        if (i) res += lt[0] * (l[i].x - l[i - 1].x);
        update(0, 0, MXL - 1, l[i].y1, l[i].y2, l[i].s);
    }
    printf("%d", res);
    return 0;
}

1167번: 트리의 지름

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


$O(n)$

http://codedoc.tistory.com/240


#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int n, r;
vector<pair<intint> > adj[100001];
int f(int h, int p) {
    int m1 = 0, m2 = 0;
    for (auto it : adj[h]) if (it.first^p) {
        m2 = max(m2, f(it.first, h) + it.second);
        if (m1 < m2) swap(m1, m2);
    }
    r = max(r, m1 + m2);
    return m1;
}
int main() {
    scanf("%d", &n);
    for (int i = 1, a, b, c; i <= n; i++) {
        scanf("%d", &a);
        while (scanf("%d", &b), b^-1) {
            scanf("%d", &c);
            adj[a].push_back({ b,c });
        }
    }
    f(1, 0);
    printf("%d", r);
    return 0;
}

7626번: 직사각형

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


$O(n\lg n)$

http://codedoc.tistory.com/421


#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MXN = 2e5;
int n, idx[MXN * 2], e, lt[MXN * 8], ct[MXN * 8];
ll res;
struct st {
    int x, y1, y2, t;
}line[MXN * 2];
void update(int hint lint rint glint grint x) {
    if (r < gl || gr < lreturn;
    if (gl <= l && r <= gr) ct[h] += x;
    else {
        update(h * 2 + 1, l, (l + r) / 2, glgrx);
        update(h * 2 + 2, (l + r) / 2 + 1, rglgrx);
    }
    if (ct[h]) lt[h] = idx[r + 1] - idx[l];
    else lt[h] = l^r ? lt[h * 2 + 1] + lt[h * 2 + 2] : 0;
}
int main() {
    scanf("%d", &n);
    for (int i = 0, x1, x2, y1, y2; i < n; i++) {
        scanf("%d%d%d%d", &x1, &x2, &y1, &y2);
        line[i] = { x1,y1,y2,1 };
        line[i + n] = { x2,y1,y2,-1 };
        idx[i] = y1;
        idx[i + n] = y2;
    }
    sort(line, line + 2 * n, [](st ist j) {return i.x < j.x; });
    sort(idx, idx + 2 * n);
    e = unique(idx, idx + 2 * n) - idx;
    for (int i = 0; i < 2 * n; i++) {
        if (i) res += (ll)lt[0] * (line[i].x - line[i - 1].x);
        update(0, 0, e - 1, lower_bound(idx, idx + e, line[i].y1) - idx,
            lower_bound(idx, idx + e, line[i].y2) - idx - 1, line[i].t);
    }
    printf("%lld", res);
    return 0;
}

4256번: 트리

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


$O(tn)$

http://codedoc.tistory.com/779와 유사하다.


#include<cstdio>
int t, n, a[1001], bi[1001];
void f(int al, int ar, int bl, int br) {
    if (al > ar) return;
    int m = bi[a[al]];
    f(al + 1, al + m - bl, bl, m - 1);
    f(al + m - bl + 1, ar, m + 1, br);
    printf("%d ", a[al]);
}
int main() {
    for (scanf("%d", &t); t--;) {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) scanf("%d", a + i);
        for (int i = 1, x; i <= n; i++) scanf("%d", &x), bi[x] = i;
        f(1, n, 1, n);
        puts("");
    }
    return 0;
}

3357번: Monument

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


$O(pqr)$

다음 두 문제의 아이디어를 조합하면 풀 수 있다.
(1) http://codedoc.tistory.com/723
(2) http://codedoc.tistory.com/911

(x,y,z)상에 0 혹은 1이 주어졌을 때 1로만 이루어진 a*a*b꼴 직육면체 중 최대 4ab를 구해보자.
편의상 xy평면과 직육면체의 정사각형인 밑면과 평행하다고 하자.
푼 다음 직육면체를 적절히 돌려 나머지 방향에서도 똑같이 풀면 될 것이다.
먼저, 각 (x,y,z)마다 해당 지점을 끝점으로 하는 (1...x,1...y,z)상의 가장 큰 정사각형 한 변 길이를 구해놓는다. ... (2)
(x,y,1...i...z)에서 (x,y,i)의 최대 정사각형 한 변 길이를 a[i]라 하고 이들로 이루어진 히스토그램상에서 최대 직사각형 넓이를 구한다. ... (1)
이렇게 하면 (x,y,1...z)가 직육면체의 끝점이 되는 (1...x,1...y,1...z) 상의 직육면체 최대 ab가 구해진다.
모든 x,y에 대해 똑같이 풀고 최대 4ab를 구한다.


#include<cstdio>
#include<algorithm>
using namespace std;
int a[3], p[3] = { 0,1,2 }, pi[3], c[3], dp[151][151][151], stk[151], top, r;
char s[151][151][152];
int main() {
    scanf("%d%d%d", a + 1, a, a + 2);
    for (int i = 1; i <= a[0]; i++) for (int j = 1; j <= a[1]; j++) scanf("%s", s[i][j] + 1);
    do {
        for (int i = 0; i < 3; i++) pi[p[i]] = i;
        for (int i = 1; i <= a[p[0]]; i++) {
            for (int j = 1; j <= a[p[1]]; j++) {
                for (int k = 1; k <= a[p[2]]; k++) {
                    c[pi[0]] = i; c[pi[1]] = j; c[pi[2]] = k;
                    int n = s[c[0]][c[1]][c[2]] == 'N';
                    dp[i][j][k] = (min({ dp[i - 1][j][k], dp[i][j - 1][k], dp[i - 1][j - 1][k] }) + 1)*n;
                    while (dp[i][j][stk[top]]>dp[i][j][k]) r = max(r, (k - 1 - stk[top - 1])*dp[i][j][stk[top--]]);
                    stk[++top] = k;
                }
                while (top) r = max(r, (a[p[2]] - stk[top - 1])*dp[i][j][stk[top--]]);
            }
        }
    } while (next_permutation(p, p + 3));
    printf("%d", 4 * r);
    return 0;
}

11873번: 최대 직사각형

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


$O(tnm)$

http://codedoc.tistory.com/723의 아이디어를 이용하자.
i행의 각 열마다 위로 연속된 1의 개수를 위 문제에서 히스토그램 높이라 생각하고 최대직사각형 넓이를 구한다.
모든 행에서 이러한 방법을 적용했을 때 최대 직사각형 넓이를 찾는다.


#include<cstdio>
#include<algorithm>
using namespace std;
int n, m;
int main() {
    while (scanf("%d%d", &n, &m) && n) {
        int r = 0, h[1001] = { 0, }, stk[1001], top;
        for (int i = 1; i <= n; i++) {
            stk[top = 0] = 0;
            for (int j = 1, x; j <= m; j++) {
                scanf("%d", &x);
                h[j] = (h[j] + 1) * x;
                while (h[stk[top]] > h[j]) r = max(r, (j - stk[top - 1] - 1)*h[stk[top--]]);
                stk[++top] = j;
            }
            while (top) r = max(r, (m - stk[top - 1])*h[stk[top--]]);
        }
        printf("%d\n", r);
    }
    return 0;
}

2970번: 두더지

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


$O(n)$

먼저, 트리의 지름(트리 상에서 가장 먼 두 정점의 경로)을 구한다.
지름의 끝 정점을 s1, s2라 하자.
s1과 s2를 잇는 경로상의 한 간선을 지워야 한다. 그러지 않는다면, 지름의 값이 가장 먼 두 정점의 거리가 될 것이기 때문이다.
간선을 하나 지웠다고 해보자. 문제는 s1을 포함하는 트리의 지름과 s2를 포함하는 트리의 지름에 의해 답이 결정된다.
s1-a1-a2-a3- ... - an-s2 (ai는 가지를 가질 수도 있다.) 모양에서
s1 ~ ai, ai~s2 트리마다의 지름을 구해야 한다.
이는 s1,s2를 시작 정점으로 하는 dfs 탐색을 이용해 해결할 수 있다.
이에 대해 간략하게 말하면 탐색에서 자신을 끝으로 하는 사슬의 최대 길이와 자식들의 지름을 가지고 갱신시키면 된다.
(본 블로그 내의 트리의 지름 1번 풀이를 참고하자. http://codedoc.tistory.com/240)
a(i-1) 과 ai를 끊었을 때의 최소 거리는 다음 세 값 중 최댓값이다.
1. s1~a(i-1) 상의 지름
2. ai~s2 상의 지름
3. s1~a(i-1) 반지름 + ai~s2 반지름 + 1
최댓값이 가장 작을 때가 답이다.
자를 곳을 결정했다면 그 간선을 제거하고 나눠진 트리에서 각각 중심점을 찾고 이으면 된다.


#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
const int MAX_N = 3e5;
vector<int> adj[MAX_N + 1];
int n, maxi, t, ck[MAX_N + 1];
int vis[MAX_N], vck;
void dfs1(int hint pint depint v) {
    if (dep > maxi) maxi = dep, t = h;
    ck[h] = 1;
    if (v != -1 && !vck) vis[dep] = h;
    if (h == v) vck = 1;
    for (auto it : adj[h])
        if (!ck[it]) dfs1(it, hdep + 1, v);
    ck[h] = 0;
}
int l[2][MAX_N + 1];
int dfs2(int hint pint idx) {
    int m1 = 0, m2 = 0;
    for (auto it : adj[h]) {
        if (it == pcontinue;
        m2 = max(m2, dfs2(it, hidx) + 1);
        if (m1 < m2) swap(m1, m2);
        l[idx][h] = max(l[idx][h], l[idx][it]);
    }
    l[idx][h] = max(l[idx][h], m1 + m2);
    return m1;
}
int main() {
    scanf("%d", &n);
    for (int i = 0, x, y; i < n - 1; i++) {
        scanf("%d %d", &x, &y);
        adj[x].push_back(y);
        adj[y].push_back(x);
    }
    int s1, s2, idx, res = 0x7fffffff;
    maxi = -1; dfs1(1, -1, 0, -1); s1 = t;
    maxi = -1; dfs1(s1, -1, 0, -1); s2 = t;
    dfs2(s2, -1, 0);
    dfs2(s1, -1, 1);
    maxi = -1; dfs1(s1, -1, 0, s2);
    for (int i = 1, tl; i <= maxi; i++) {
        tl = max({ (l[0][vis[i - 1]] + 1) / 2 + (l[1][vis[i]] + 1) / 2 + 1,
            l[0][vis[i - 1]],l[1][vis[i]] });
        if (res > tl) res = tl, idx = i;
    }
    s1 = vis[idx - 1]; s2 = vis[idx];
    int h1, h2, r1, r2;
    ck[s2] = 1;
    maxi = -1; dfs1(s1, -1, 0, -1); h1 = t;
    maxi = -1; dfs1(h1, -1, 0, -1); h2 = t;
    maxi = -1; vck = 0; dfs1(h1, -1, 0, h2); r1 = vis[maxi / 2];
    ck[s2] = 0; ck[s1] = 1;
    maxi = -1; dfs1(s2, -1, 0, -1); h1 = t;
    maxi = -1; dfs1(h1, -1, 0, -1); h2 = t;
    maxi = -1; vck = 0; dfs1(h1, -1, 0, h2); r2 = vis[maxi / 2];
    printf("%d\n%d %d\n%d %d", res, s1, s2, r1, r2);
    return 0;
}