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

 

8981번: 입력숫자

첫 줄에는 정수 N이 제시되어 있고, 그 다음 줄에는 N개의 양의 정수가 빈칸을 사이에 두고 기록되어 있어야 한다. 만일 입력을 생성하는 mystery.c의 입력파일 X가 없는 경우에는 음수인 -1 을 첫 줄

www.acmicpc.net

 

 

[난이도] Gold4
[유형] 구현

[풀이]
코드를 보고 역추적하는 문제이다. 인덱스와 값의 관계를 잘 파악해야 한다.
어떤 Y에 대해서도 X는 무조건 존재하므로 -1인 출력은 신경쓰지 않아도 된다.

 

#include <cstdio>
int N,a[30],b[30];
int main(){
    scanf("%d",&N);
    for(int i=0;i<N;i++) scanf("%d",&a[i]);

    int idx=0;
    b[0]=a[0];
    for(int j=1;j<N;j++){
        int mv = b[idx];
        idx=(idx+mv)%N;
        while(b[idx]!=0) idx=(idx+1)%N;
        b[idx]=a[j];
    }
    printf("%d\n",N);
    for(int i=0;i<N;i++) printf("%d ",b[i]);
}


https://github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold4/8981.cpp

 

 

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

 

1577번: 도로의 개수

첫째 줄에 도로의 가로 크기 N과 세로 크기 M이 주어진다. N과 M은 100보다 작거나 같은 자연수이고, 둘째 줄에는 공사중인 도로의 개수 K가 주어진다. K는 0보다 크거나 같고, 100보다 작거나 같은

www.acmicpc.net

 

[난이도] Gold4
[유형] DP

[풀이]
map[100][100][2] 배열을 선언해서
(y,x) -> (y+1,x) 길이 막혀있는 경우 map[y][x][0]=1,
(y,x) -> (y,x+1) 길이 막혀있는 경우 map[y][x][1]=1 로 체크한 뒤
DP로 모든 경우를 구해주면 된다.

 

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
using ll = long long;
int dy[2]={1,0},dx[2]={0,1};
int K,N,M,map[101][101][2];
ll dp[101][101];
ll sol(int y,int x){
    if(y==N&&x==M) return 1;
    ll& ret = dp[y][x];
    if(ret!=-1) return ret;
    ret = 0;
    for(int i=0;i<2;i++){
        if(!map[y][x][i]){
            int ny=y+dy[i],nx=x+dx[i];
            if(ny<=N&&nx<=M) ret+=sol(ny,nx);
        }
    }
    return ret;
}
int main(){
    scanf("%d%d%d",&N,&M,&K);
    while(K--){
        int a,b,c,d;
        scanf("%d%d%d%d",&a,&b,&c,&d);
        if(a>c)swap(a,c);
        else if(b>d)swap(b,d);
        if(a<c) map[a][b][0]=1;
        else if(b<d) map[a][b][1]=1;
    }
    memset(dp,-1,sizeof(dp));
    printf("%lld",sol(0,0));
}



https://github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold4/1577.cpp

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

 

1153번: 네 개의 소수

임의의 자연수가 주어지면, 이를 네 개의 소수의 합으로 분해하는 프로그램을 작성하시오. 예를 들어 38 = 5 + 7 + 13 + 13이 된다.

www.acmicpc.net

 

[난이도] Gold4
[유형] 정수론

[풀이]
골드바흐의 추측이라는 정수론 개념을 이용해서 풀어야 하는 문제이다.
https://ko.wikipedia.org/wiki/%EA%B3%A8%EB%93%9C%EB%B0%94%ED%9D%90%EC%9D%98_%EC%B6%94%EC%B8%A1

일단 시간내에 소수를 구하기 위해 에라토스테네스의 체를 이용해 소수를 미리 구해준다.

골드바흐의 추측 : '2보다 큰 모든 짝수는 두 소수의 합으로 표현가능하다'

4개 소수의 합으로 표현하기 위해서 N은 무조건 8보다는 커야 한다.
N이 홀수인 경우, N에서 2,3을 빼주어서 짝수를 만든 뒤 N-5를 두개의 소수로 만들 수 있는 짝을 찾는다.
N이 짝수인 경우, N에서 2,2를 빼준 뒤에 N-4를 두개의 소수로 만들 수 있는 짝을 찾는다.

 

#include <cstdio>
#include <vector>
using namespace std;
int N;
bool a[1000001];
int main(){
    scanf("%d",&N);
    a[0]=a[1]=1;
    for(int i=2;i<=N;i++){
        for(int j=2*i;j<=N;j+=i) a[j]=1;
    }
    vector<int> ans;
    if(N<8) puts("-1");
    else{
        if(N%2){
            ans.push_back(2);
            ans.push_back(3);
            for(int i=2;i<=N;i++){
                if(!a[i] && !a[N-5-i]){
                    ans.push_back(i);
                    ans.push_back(N-5-i);
                    break;
                }
            }
        }else{
            ans.push_back(2);
            ans.push_back(2);
            for(int i=2;i<=N;i++){
                if(!a[i] && !a[N-4-i]){
                    ans.push_back(i);
                    ans.push_back(N-4-i);
                    break;
                }
            }            
        }
    }
    for(auto p : ans) printf("%d ",p);
}



https://github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold4/1153.cpp

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

 

14267번: 회사 문화 1

영선회사에는 매우 좋은 문화가 있는데, 바로 상사가 직속 부하를 칭찬하면 그 부하가 부하의 직속 부하를 연쇄적으로 칭찬하는 내리 칭찬이 있다. 즉, 상사가 한 직속 부하를 칭찬하면 그 부하

www.acmicpc.net

 

 

[난이도] Gold4
[유형] DFS

[풀이]
인접리스트를 이용해 칭찬 그래프를 만들고 칭찬을 받은 사람부터 dfs를 시작해
방문하는 모든 부하들에게 칭찬을 더해주면 된다.
이 때, 칭찬의 총 갯수 M마다 dfs를 돌면 시간초과가 나므로 사람 i에 대한 칭찬을 미리 모두 더한 뒤
dfs를 돌려야 한다.

 

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
int N,M,ans[100001],s[100001];
vector<int> adj[100001];
void dfs(int n,int k){
    ans[n]+=k;
    for(auto nxt : adj[n]) dfs(nxt,k);
}

int main(){
    scanf("%d%d",&N,&M);
    
    for(int i=1;i<=N;i++){
        int u;
        scanf("%d",&u);
        if(u!=-1) adj[u].push_back(i);
    }
    while(M--){
        int a,w;
        scanf("%d%d",&a,&w);
        s[a]+=w;
    }
    for(int i=2;i<=N;i++){
        if(s[i]>0) dfs(i,s[i]);
    }
    for(int i=1;i<=N;i++) printf("%d ",ans[i]);
}


https://github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold4/14267.cpp

 

 

 

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

 

15483번: 최소 편집

첫째 줄과 둘째 줄에 두 문자열이 주어진다. 문자열은 알파벳 소문자로만 이루어져 있으며, 최대 1000글자로 이루어져 있다.

www.acmicpc.net

 

[난이도] Gold4
[유형] DP

[풀이]
기본 LCS를 변경한 DP로 풀 수 있다.

DP[i][j] : 바꿔야할 문자열이 a, 목표 문자열이 b일때 a[1...i],b[1...j]까지의 a,b에 대한 최소 편집 개수
a[i]==b[j] 이면 DP[i][j] = DP[i-1][j-1] 이며
아닌 경우 DP[i-1][j-1] , DP[i-1][j] , DP[i][j-1] 중 최솟값에 1을 더한 값이 된다.
DP[i-1][j-1]인 경우는 a[i]를 b[j]로 바꾸는 연산, DP[i-1][j],DP[i][j-1]인 경우는 문자 하나를 추가하는 연산이다.

 

#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
string a,b,c;
int dp[1001][1001];
int main(){
    cin >> a >> b;
    a='A'+a;
    b='B'+b;
    int n=a.size(), m=b.size();
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(i==0&&j==0) continue;
            if(i==0){
                dp[i][j]=j;
                continue;
            }
            if(j==0){
                dp[i][j]=i;
                continue;
            }
            if(a[i]==b[j]) dp[i][j] = dp[i-1][j-1];
            else dp[i][j] = min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1;
        }
    }
    cout << dp[n-1][m-1] << endl;;
}

 


https://github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold4/15483.cpp

https://codeforces.com/contest/1472/problem/D

 

Problem - D - Codeforces

 

codeforces.com

 

[난이도] Div.3
[유형] Greedy

[풀이]
홀수, 짝수인 숫자를 따로 vector에 보관 후 정렬하고,
Alice 차례일때 현재 홀수중 최댓값이 짝수중 최댓값보다 크다면 홀수를 선택해서 Bob이 선택못하도록 하고,
짝수가 더크다면 짝수를 선택하는 방식으로 하는것이 Alice에게 최적이다.
Bob의 차례인 경우엔 그 반대로 하면 된다.

다른 풀이를 보고 알 수 있었는데
홀수,짝수 상관없이 정렬 후 큰 수부터 선택해도 Alice,Bob 모두 optimal 하므로 이 방식으로 풀어도 된다.

 

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
using ll = long long;
int tc,N;
int main(){
    scanf("%d",&tc);
    
    while(tc--){
        scanf("%d",&N);
        vector<ll> odd,even;
        for(int i=0;i<N;i++){
            ll v;
            scanf("%lld",&v);
            if(v%2) odd.push_back(v);
            else even.push_back(v);
        }
        sort(odd.begin(),odd.end());
        sort(even.begin(),even.end());
        
        int curo=odd.size()-1,cure=even.size()-1;
        ll alice=0,bob=0;
        for(int i=0;;i++){
            if(curo<0&&cure<0) break;
            if(i%2==0){
                if(curo<0){
                    alice+=even[cure--];
                    continue;
                }
                if(cure<0){
                    curo--;
                    continue;
                }

                if(odd[curo] <= even[cure]){
                    alice+=even[cure--];
                }else{
                    curo--;
                }
            }else{
                if(curo<0){
                    cure--;
                    continue;
                }
                if(cure<0){
                    bob+=odd[curo--];
                    continue;
                }

                if(odd[curo] >= even[cure]){
                    bob+=odd[curo--];
                }else{
                    cure--;
                }
            }
        }
        if(alice>bob) puts("Alice");
        else if(alice<bob) puts("Bob");
        else puts("Tie");
        //printf("alice:%d, bob:%d\n",alice,bob);
    }
}



https://github.com/has2/Problem-Solving/blob/master/codeforces/Round693-Div.3/D.cpp

https://codeforces.com/contest/1472/problem/C

 

Problem - C - Codeforces

 

codeforces.com

 

[난이도] Div.3
[유형] DP

[풀이]
DP(i) (1<=i<=N) : index i를 선택했을 얻을 수 있는 점수.
점화식 : DP(i) = A[i] + DP(i+A[i])

 

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int tc,N,a[200001],dp[200001];
int sol(int n){
    if(n > N) return 0;
    int& ret = dp[n];
    if(ret!=-1) return ret;
    ret = a[n]+sol(n+a[n]);
    return ret;
}
int main(){
    scanf("%d",&tc);
    while(tc--){
        scanf("%d",&N);
        for(int i=1;i<=N;i++) scanf("%d",&a[i]);
        memset(dp,-1,sizeof(dp));
        int ans = 0;
        for(int i=1;i<=N;i++) ans = max(ans,sol(i));
        printf("%d\n",ans);
    }
}

 


https://github.com/has2/Problem-Solving/blob/master/codeforces/Round693-Div.3/C.cpp


https://codeforces.com/contest/1472/problem/B

 

Problem - B - Codeforces

 

codeforces.com

 

[난이도] Div.3
[유형] DP

[풀이]
전체 합이 홀수인지, 짝수인지를 따져가며 풀이도 있는데 생각이 안나서 DP로 풀었다.

DP(n1,n2) : 1이 n1개, 2가 n2개 남았을 때 캔디를 동일하게 분배가 가능하면 true, 아니면 false

DP(n1,n2) = DP(n1-2,n2) A에게 1을 1개, B에게 1을 1개 준 경우
|| DP(n1-2,n2-1) A에게 1을 2개, B에게 2를 1개 준 경우
|| DP(n1,n2-2) A에게 2를 1개, B에게 2를 1개 준 경우
(위 세가지 케이스중 한가지만 true여도 DP(n1,n2)는 true가 된다.)

 

#include <cstdio>
#include <cstring>
int tc,N,a[3],dp[101][101];
int sol(int n1,int n2){
    int& ret=dp[n1][n2];
    if(ret!=-1) return ret;
    if(n1==0&&n2==0) return ret=1;
    
    if(n1-2>=0 && sol(n1-2,n2)) return ret=1;
    if(n1-2>=0 && n2-1>=0 && sol(n1-2,n2-1)) return ret=1;
    if(n2-2>=0 && sol(n1,n2-2)) return ret=1;
    return ret=0;
}
int main(){
    scanf("%d",&tc);
    while(tc--){
        scanf("%d",&N);
        a[1]=a[2]=0;
        while(N--){
            int v;
            scanf("%d",&v);
            a[v]++;
        }
        memset(dp,-1,sizeof(dp));
        if(sol(a[1],a[2])) puts("YES");
        else puts("NO");
    }
}


https://github.com/has2/Problem-Solving/blob/master/codeforces/Round693-Div.3/B.cpp

+ Recent posts