본문 바로가기

알고리즘

boj 20641. Sleeping Cows

www.acmicpc.net/problem/20641

 

USACO 문제입니다.

 

 

Dynamic programming 으로 해결할 수 있는 문제입니다.

 

문제 해결 관찰)

 

1. $ s_{j} $ 가 $ t_{i} $ 안에 배정되는 모든 barn 의 크기를 오름차순 시키고 배정할 때 괄호문자열처럼 되어야 합니다.

   $ s_{i} $ 는 (

   $ t_{i} $ 는 ) 

 

2. 배정되지 못한 barn 들은 $ max(t_{i}) $ < $ min(s_{i}) $ 를 만족해야 합니다. 즉 $ t_{i} $ 가 쭉 주어지다 $ s_{i} $ 가 주어져야 합니다.

 

주어진 $ s_{i} $ 와 $ t_{i} $ 를 모두 합쳐서 정렬을 합니다 ( $ s_{i} $ 와 $ t_{i} $ 의 값이 같다면 $ s_{i} $ 가 먼저 오도록 한다 )

 

그리고 $ dp[i][j][t] $ 배열을 선언합니다.

 

$ dp[i][j][t] $ 에서

$ i $ 는 배정되는 모든 barn 의 괄호문자열 값이고 ( $ s_{i} $ 면 + $ t_{i} $ 면 - )

$ j $ 는 배정되지 못한 barn 의 값 ( $ t_{i} $ 면 + $ s_{i} $ 면 - )

$ t $ 는 배정되지 못한 barn 의 타입 ( $ t_{i} $ 가 진행중이면 0 $ s_{i} $  진행중이면 1 )

 

 

그럼 문제가 생깁니다. 이렇게 진행하면 시간복잡도가 $ N^{3} $ 이 아닐까요?

 

근데 좀 들여다보면 $ i $ 배열에서는 $ s_{i}  - t_{i} $ 고 $ j $ 배열에선 $ t_{j} - s_{j} $ 입니다.

즉 $ i $ - $ j $ 를 하면 $ s_{i} + s_{j} - ( t_{i} + t_{j} ) $  이기 때문에 $ i $ 값이 정해지면 $ j $ 값도 정해지게 됩니다.

 

즉 이를 이용하면 $ N^{2} $ 시간복잡도에 해결할 수 있습니다.

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include <bits/stdc++.h>
using namespace std;
typedef long long int lld;
typedef pair<int,int> pi;
typedef pair<lld,lld> pl;
typedef pair<int,lld> pil;
typedef pair<lld,int> pli;
typedef vector<int> vit;
typedef vector<vit> vitt;
typedef vector<lld> vlt;
typedef vector<vlt> vltt;
typedef vector<pi> vpit;
typedef vector<vpit> vpitt;
typedef long double ld;
#define x first
#define y second
#define pb push_back
#define all(v) v.begin(), v.end()
#define sz(x) (int)x.size()
#define mk(a,b) make_pair(a,b)
bool isrange(int y,int x,int n,int m){
     if(0<=y&&y<n&&0<=x&&x<m) return true;
     return false;
}
int dy[4= {1,0,-1,0},dx[4]={0,1,0,-1},ddy[8= {1,0,-1,0,1,1,-1,-1},ddx[8= {0,1,0,-1,1,-1,1,-1};
 
const lld mod = 1e9 + 7;
const int MAX = 3030;
lld dp[MAX][MAX][2];
vector<pi> v;
bool tmr(pi a,pi b){
    if(a.x!=b.x) return a.x < b.x;
    return a.y < b.y;
}
void solve(int tc){
    int n;
    scanf("%d",&n);
    for(int e=1;e<=n;e++){
        int r;
        scanf("%d",&r);
        v.push_back(mk(r,0));
    }
    for(int e=1;e<=n;e++){
        int r;
        scanf("%d",&r);
        v.push_back(mk(r,1));
    }
    sort(all(v),tmr);
    dp[0][0][0= 1;
    int tot = 0;
    for(int e=0;e<sz(v);e++){
        int ty = v[e].y;
        if(ty==0){
            for(int q=0;q<=n;q++){
                int r = q - (tot+1);
                if(r>=0) dp[q][r][0= dp[q][r][1= 0;
            }
        }else{
            for(int q=0;q<=n;q++){
                int r = q - (tot-1);
                if(r>=0) dp[q][r][0= dp[q][r][1= 0;
            }
        }
        for(int q=0;q<=n;q++){
            int r = q - tot;
            if(r<0continue;
            if(ty==0){
                dp[q+1][r][0= (dp[q+1][r][0]+dp[q][r][0]*(q+1))%mod;
                dp[q+1][r][1= (dp[q+1][r][1]+dp[q][r][1]*(q+1))%mod;
                if(r) dp[q][r-1][1= (dp[q][r-1][1]+dp[q][r][0]+dp[q][r][1])%mod;
            }else{
                if(q){
                    dp[q-1][r][0= (dp[q-1][r][0]+dp[q][r][0])%mod;
                    dp[q-1][r][1= (dp[q-1][r][1]+dp[q][r][1])%mod;
                }
                dp[q][r+1][0= (dp[q][r+1][0]+dp[q][r][0])%mod;
            }
        }
        if(ty==0) tot++;
        else tot--;
    }
    lld ans = (dp[0][0][0]+dp[0][0][1])%mod;
    printf("%lld\n",ans);
}
 
 
int main(void){
 
//    ios_base :: sync_with_stdio(false);
//    cin.tie(NULL);
//    cout.tie(NULL);
 
    int tc = 1;
    /*
        cin >> tc;
    */
    for(int test_number=1;test_number<=tc;test_number++){
        solve(test_number);
    }
    return 0;
}
 
cs

'알고리즘' 카테고리의 다른 글

Atcoder Regular 110 F - Esoswap  (0) 2020.12.06
DSU tree  (0) 2020.10.04
백준 1536번 Dance, Dance  (0) 2020.09.23
조금 신기한 분할정복  (0) 2020.09.13
SCPC 3회 1차 2차 예선 풀이  (1) 2020.08.31