백준 재활 연습 - 1일차

2020. 11. 18. 22:46PS/BaekJoon Practice

이번에 KOI에서 잘 못해서 빡친 나는 이번년도에 코포 오렌지 달고 간다는 생각으로 재활훈련을 시작했다.

처음 셋은 조합론 + dp 조합이다.

운으로 올솔하였다.

 

1. www.acmicpc.net/problem/15989

 

15989번: 1, 2, 3 더하기 4

정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 4가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다. 합을 이루고 있는 수의 순서만 다른 것은 같은 것으로 친다. 1+1+1+1 2+1+1 (1+1+2, 1+2+1) 2+2

www.acmicpc.net

처음 봤을 때는 만만치 않은 문제처럼 보이나, 순서를 고려해주면 아주 쉽게 풀 수 있는 문제이다.

먼저 우리가 신경써야 할 것은 순서에 의한 중복되는 경우의 수인데, 순서를 어떤 기준을 세워서 나타내어 중복을 없앴다.

나는 이 식이 항상 내림차순으로 더한다고 기준을 정하였다.( ex) 5=3+2=3+1+1=2+2+1=2+1+1+1)

그리고 정의해주고 식만 세우면 아주 쉬운 문제가 되버린다.

dp[i][j] = 더해서 i가 되고 마지막으로 더한 숫자가 j일때 경우의 수

자세한 점화식은 기준을 확실하게 이해했다면 코드를 보고 바로 이해가 될 것이다.

#include <bits/stdc++.h>
#define MEM 10005
#define f first
#define s second
#define sanic ios_base::sync_with_stdio(0)
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
const ll INF = 1e9+9;
ll n,y,c,t;
ll dp[MEM][3];
main(){
    sanic;cin.tie(0);
    dp[1][0] = 1;
    dp[2][0] = 1;
    dp[2][1] = 1;
    dp[3][0] = 2;
    dp[3][2] = 1;
    for(int i=4; i<MEM; i++){
        dp[i][0] = dp[i-1][0]+dp[i-1][1]+dp[i-1][2];
        dp[i][1] = dp[i-2][1]+dp[i-2][2];
        dp[i][2] = dp[i-3][2];
    }
    cin >> t;
    while(t--){
        cin >> n;
        cout << dp[n][0]+dp[n][1]+dp[n][2] << '\n';
    }
}

2. www.acmicpc.net/problem/2482

 

2482번: 색상환

첫째 줄에 N색상환에서 어떤 인접한 두 색도 동시에 선택하지 않고 K개의 색을 고를 수 있는 경우의 수를 1,000,000,003 (10억 3) 으로 나눈 나머지를 출력한다.

www.acmicpc.net

전형적인 dp문제이다. ㅋㅋ

굳이 풀이를 하자면 

dp[i][j] = i개의 색상에서 j개 고를 때 경우의 수

로 캐이스를 따져 점화식을 세우면 된다.

자세한건 코드 참고.

#include <bits/stdc++.h>
#define MEM 1001
#define f first
#define s second
#define sanic ios_base::sync_with_stdio(0)
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
const ll MOD = 1e9+3;
ll n,m;
ll dp[MEM][MEM];
main(){
    sanic;cin.tie(0);
    cin >> n >> m;
    for(int i=1; i<=n; i++)
        dp[i][1] = i;
    for(int i=1; i<=n; i++)
        for(int j=2; j<=m; j++)
            if(j<=i/2)
                dp[i][j] = (dp[i-1][j]+dp[i-2][j-1]+MOD)%MOD;
    cout << dp[n][m];
}

3. www.acmicpc.net/problem/19535

 

19535번: ㄷㄷㄷㅈ

첫 번째 줄에 주어진 트리가 D-트리라면 D, G-트리라면 G, DUDUDUNGA-트리라면 DUDUDUNGA를 출력한다.

www.acmicpc.net

G-ㅈ을 만들기 위해서는 중심노드 하나와 중심노드의 degree가 3이상이어야 한다. 이때 연결되어 있는 노드들 중 3개를 고르는 경우의 수가 G트리의 갯수가 된다.

D-D트리는 선형으로 연결되어 있는 노드 3개따리 트리를 찾아야 한다. 일단 인접한 정점 두개를 잡은 뒤 각 노드의 degree-1을 곱한 것이 두 정점의 D트리를 만드는 경우의 수가 된다. 이를 모두 합한게 D트리의 총갯수가 된다.

따라서 트리를 만들어서 각 노드마다 degree를 구하여 G, D트리의 갯수를 구하면 된다.

자세한건 코드 참고.

#include <bits/stdc++.h>
#define MEM 300001
#define f first
#define s second
#define sanic ios_base::sync_with_stdio(0)
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
const ll MOD = 1e9+3;
ll n,m;
ll d,j;
vector<ll> g[MEM];
main(){
    sanic;cin.tie(0);
    cin >> n;
    for(int i=0; i<n-1; i++){
        ll u,v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for(int i=1; i<=n; i++){
        ll f=g[i].size();
        j += (f*(f-1)*(f-2))/6LL;
        for(int l=0; l<f; l++){
            ll nt=g[i][l];
            if(i>nt) continue;
            d += (g[nt].size()-1)*(f-1);
        }
    }
    if(d>3*j) cout << "D";
    else if(d<3*j) cout << "G";
    else cout << "DUDUDUNGA";
}

 

스코어보드

 

'PS > BaekJoon Practice' 카테고리의 다른 글

알고리즘 공부 : LIS  (0) 2020.12.25
백준 연습 #2  (0) 2020.10.02
백준 연습 #1  (1) 2020.10.02