풀이


정말 고등학교 1년만 제대로 다니면 누구나 풀 수 있는 몇 안 되는 문제가 아닐까싶다.


소스 코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <math.h>
int d(int n) {
    if(n%2==0return 1;
    else return 0;
}
int main() {
    int a, b, c, q1, q2;
    double p,q;
    scanf("%d %d %d",&a,&b,&c);
    if (b*- 4 * a*> 0) {
        q1 = (-+ (int)sqrt(b*- 4 * a*c)) / (2 * a);
        q2 = (-- (int)sqrt(b*- 4 * a*c)) / (2 * a);
        p = ((-+ sqrt(b*- 4 * a*c)) / (2 * a)) - q1;
        q = ((-- sqrt(b*- 4 * a*c)) / (2 * a)) - q2;
        if (p || q) printf("둘다틀렸근"); 
        else if (d((-+ (int)sqrt(b*- 4 * a*c)) / (2 * a))&&d((-- (int)sqrt(b*- 4 * a*c)) / (2 * a))) printf("이수근");
        else printf("정수근");
    }
    else {
        printf("둘다틀렸근");
    }
    return 0;
}
cs


풀이


r[j] + ds[r[j]]>=r[i+1]


이 코드가 핵심이다. 현재위치 + 사정거리 가 다음 위치보다 짧이지는 순간이 존재한다면 바로 영창을 보내면 되는 문제다. 물론 같은 위치에 있는 사람들중 제일 잘 던지는 사람이 던지는 걸로 말이다.(여기서 해싱 사용)


소스 코드


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
#include <stdio.h>
int r[30001];
int ds[1000001];
int main(){
    int n,i,j,d,cnt=0,sum=0;
    scanf("%d",&n);
    for(i = 0; i < n; i++scanf("%d",&r[i]);
    if(n!=1) {
    for(i = 0; i < n-1; i++) {
        scanf("%d",&d);
        if(ds[r[i]] < d) ds[r[i]] = d;
    }
    for(i = 0; i < n-1; i++){
        if(r[i] == r[i+1]) continue;
        for(j = 0; j <= i; j++){
            if(r[j] == r[j+1]) continue;
            if(r[j] + ds[r[j]]>=r[i+1]) {cnt = 1break;}
        }
        if(!cnt) {printf("엄마 나 전역 늦어질 것 같아"); return 0;}
        cnt=0;
    }
    }
    printf("권병장님, 중대장님이 찾으십니다");
return 0;    
}
cs



풀이


이것은 dp로! 이건 처음에 설정을 잘해줘야 하는데, 첫 경우를 S, E, B를 타고 접근한게 아니라면 처음부터 생기는 경우만 존재(1)하고 타고 접근했다면 지금까지 왔던거에 1을 더함(이동하는 경우)으로 설정한다. 그 뒤부터는 알맞게 점화식을 세우면 된다.


소스코드


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
#include <stdio.h>
char ch[4000][4000];
char tmp[4000];
int dp[4000][4000];
int main(){
    int n, m, i, j;
    dp[1][1= 1;
    scanf("%d %d",&n,&m);
    for(i = 1; i <= n; i++){
        scanf("%s",tmp);
        for(j = 1; j <= m; j++){
                ch[i][j] = tmp[j-1];
        }
    }
    for(i = 2; i <=n; i++) {
        if(ch[i-1][1== 'S'||ch[i-1][1]=='B') dp[i][1= (dp[i-1][1]+1)%1000000009;    
        else dp[i][1= 1;
    }
    for(j = 2; j <=m; j++) {
        if(ch[1][j-1== 'E'||ch[1][j-1]=='B') dp[1][j] = (dp[1][j-1]+1)%1000000009;    
        else dp[1][j] = 1;
    }
    for(i = 2; i <= n; i++){
        for(j = 2; j <= m; j++){
            if(ch[i][j-1]=='E'||ch[i][j-1]=='B') dp[i][j] += (dp[i][j-1]);
            if(ch[i-1][j]=='S'||ch[i-1][j]=='B') dp[i][j] += (dp[i-1][j]);
            if(ch[i][j]=='X') dp[i][j] += 1;
            else dp[i][j]+=1;
            dp[i][j] %= 1000000009;
        }
    }
    printf("%d",dp[n][m]);
    return 0;
}
cs



풀이


요즘 DP문제가 너무 재밌네요ㅋㅋ 이 문제는 입력받는 배열이랑 dp 배열을 만들고 min함수를 만든다음에 현재 i번째에서의 최소는 i-1번째에서 이번과 겹치치 않는 부분중 최소와의 합이다. 라는 생각으로 코딩하면 쉽게 풀립니다. 자세한 건 말보다는 코드로!


소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
int dp[1003][4];
int arr[1003][4];
int min(int p, int q){
    return (p > q) ? q:p;    
}
int main(){
    int n,i,j;
    scanf("%d",&n);
    for(i = 1; i <= n; i++for(j = 1; j <= 3; j++scanf("%d",&arr[i][j]);
    dp[1][1= arr[1][1];
    dp[1][2= arr[1][2];
    dp[1][3= arr[1][3];
    for(i = 2; i<=n; i++){
        for(j = 1; j <= 3; j++){
            if(j==1) dp[i][j] = arr[i][j] + min(dp[i-1][2],dp[i-1][3]);
            else if(j==2) dp[i][j] = arr[i][j] + min(dp[i-1][1],dp[i-1][3]);    
            else if(j==3) dp[i][j] = arr[i][j] + min(dp[i-1][1],dp[i-1][2]);    
        }
    }
    printf("%d",min(min(dp[n][1],dp[n][2]),dp[n][3]));
    return 0;
}
cs


 

풀이

 

미로찾기와 비슷한 알고리즘으로 풉니다. 재귀함수를 이용할 때 주의할 점은 Recursive case(언젠가는 수렴해야 하는 지점)를 잘 설정해야 한다는 것이고요. 동서남북으로 말이 이동할 수 있다고 했으니 s(p+1,q) - 남 , s(p,q+1) - 동, s(p-1,q) - 북, s(p,q-1) - 서 이렇게 방향을 설정해서 재귀호출합니다. 근데 여기서 한 가지 의문이 들 수 있겠네요. 길을 잘 못 들면? 어떻게 최댓값을 구하지? 초기화는 어떻게? 각 장소마다 값을 저장할 수 있는 지점이 있어야 하지 않을까?' 그 해답을 저는 지역변수를 만들자!'라는 생각에서 얻었습니다. 지역변수는 중괄호 블록내에서만 메모리 공간이 할당되기때문에 재귀호출한 함수안에서의 메모리 영역에 값과 그 이전 함수에 메모리 영역에 값에는 다른 값들이 저장되게 됩니다. 그러면 다시 돌아오는 과정이 간편하고 더 이상 동서남북 어느 곳에도 이동할 수 있는 길이 없을 때, 최댓값인지만 비교해주면 문제가 깔끔히 해결됩니다.

 

소스 코드

 

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
#include <stdio.h>
char ch[21][21];
char str[21];
int st[26];
int n,max;
int s(int p, int q){
    if (ch[p][q] == '\0'return 0;
    else if (st[ch[p][q] - 65!= 0return 0;
    else {
        st[ch[p][q] - 65= 1;
        n++;
        if ((ch[p + 1][q] == '\0' || st[ch[p + 1][q] - 65!= 0&& (ch[p - 1][q] == '\0' || st[ch[p - 1][q] - 65!= 0&& (ch[p][q + 1== '\0' || st[ch[p][q + 1- 65!= 0&& (ch[p][q - 1== '\0' || st[ch[p][q - 1- 65!= 0)) {
            if (max < n) max = n;
            return 0;
        }//더 이상 길이 없을 때 최댓값인지 비교
        int k = n;
        int st1[26];
        for (int i = 0; i < 26; i++) st1[i] = st[i];
        s(p, q + 1);
        n = k;
        for (int i = 0; i < 26; i++) st[i] = st1[i];
        s(p + 1, q);
        n = k;
        for (int i = 0; i < 26; i++) st[i] = st1[i];
        s(p - 1, q);
        n = k;
        for (int i = 0; i < 26; i++) st[i] = st1[i];
        s(p, q - 1);
        n = k;
        for (int i = 0; i < 26; i++) st[i] = st1[i];
        return 0;
    }
}
int main(){
    int i, j, p, q;
    scanf("%d %d",&p,&q);
    for (i = 0; i < p; i++){
        scanf("%s", str);
        for (j = 0; j < q; j++)
            ch[i][j] = str[j];
    }
    s(00);
    printf("%d",max);
    return 0;
}
cs

 

풀이

 

컴퓨터는 원 순열을 표현할 수 없으니 직순열로 바꿔 문제를 해결합니다. vector를 사용하여 m번째 사람을 출력함과 동시에 순열에서 제거 시킵니다. 인덱스 번호는 런타임 에러가 발생하지 않도록 벡터의 사이즈로 나눈 나머지를 유지합니다.

{ j = (j + k - 1) % v.size() }

 

소스 코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <vector>
using namespace std;
vector<int> v;
int main() {
    int n, k, su, i,j=0;
    scanf("%d %d",&n,&k);
    for (i = 1; i <= n; i++) v.push_back(i);
    printf("<");
    while (v.size()-1) {
        j = (j + k - 1) % v.size();
        printf("%d, ",v[j]);
        v.erase(v.begin()+j);
    }
    printf("%d>",v[0]);
    return 0;
}
cs

 

풀이

 

이 문제는 일반적인 방법으로는 풀 수 없습니다. 왜냐하면 n이 10만까지여서 이중 for문을 쓰면 시간 초과가 뜹니다. 단일 for문으로 이 문제를 풀려면 식을 따로 만들어야 하는 데 2,3,4,5를 입력 받았다고 가정했을 때, 2*3 + 2*4 + 2*5 + 3*4 + 3*5 + 4*5 이므로 공통인수를 뽑아 인수분해하면 2(3+4+5)+3(4+5)+4*5 입니다. 여기서 발견할 수 있는 규칙은 시그마 k번째 수 * (시그마 k+1번째 ~ n번째 수) 입니다. 이렇게 식을 세워서 계산하면 쉽게 풀립니다.

 

소스 코드

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <vector>
using namespace std;
vector<int> v;
int main() {
    int n,i,j,su;
    long long sum = 0,hap=0;
    scanf("%d",&n);
    for (i = 0; i < n; i++scanf("%d",&su), v.push_back(su), sum+=su;
    for (i = 0; i < n-1; i++) sum -= v[i], hap += v[i] * sum;
    printf("%lld",hap);
    return 0;
}
cs

 

풀이

 

단순구현 문제이다.

 

소스 코드

 

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int arr[26];
int main() {
    int n,i,count=1;
    char ch[31];
    scanf("%d",&n);
    while (n--scanf("%s",ch), arr[ch[0]-97]++;
    for (i = 0; i < 26; i++if (arr[i] >= 5printf("%c",i+97),count=0;
    if (count) printf("PREDAJA");
    return 0;
}
cs

풀이

 

c++에서 지원하는 알고리즘 자료구조를 받아와서 key값을 string, value값을 int로 하는 map을 구현합니다. 그러면 map을 인덱스 값이 string, 그 안에 값이 int인 배열처럼 쓸 수 있습니다. map과 배열의 차이점은 map은 값을 넣어줄 때 정렬이 된다는 점입니다. 그리고 string을 사용하면 iostream을 받아와야 되고 scanf(), gets(),printf()를 사용할 수 없습니다. 이 점에 주의하면 시간 초과없이 간결하게 코드를 짤 수 있습니다.

 

소스 코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
map<stringint> m;
string str[100000];
string str1;
int main() {
    int n,i;
    scanf("%d",&n);
    for(i = 0; i < n; i++cin >> str[i], m[str[i]]++;
    for (i = 0; i < n - 1; i++cin >> str1, m[str1]--;
    for (i = 0; i < n; i++) {
        if (m[str[i]] == 1) {
            cout << str[i];
            break;
        }
        }
    return 0;
}
cs

 

풀이

 

이 문제는 map을 써도 간단히 풀리지만 더 간단히 푸는 방법이 있습니다. 바로 XOR 연산을 이용하는 건데요. XOR 연산은 다르면 1, 같으면 0을 반환하는 연산입니다. 먼저 XOR의 몇가지 규칙을 알아보자면 1. 0 ^ a = a, 2. a^a = 0, 3. a^b^a^b = 0, 4. a^b^a^b^c = c 입니다. 문자열의 각 문자는 다 아스키 코드 값을 가지게 됩니다. 아스키 코드값을 이진수로 변환해서 비트 연산하면 결국 마지막에는 이름이 호명되지 않은 사람의 이름만이 남게 됩니다.

 

소스 코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
char a[22], s[22];
int main() {
    int n, i;
    scanf("%d",&n);
    n *= 2;
    for (n--; n--;) {
        scanf("%s", s);
        for (i = 0; s[i]; i++) a[i] ^= s[i];
    }
    printf("%s",a);
    return 0;
}
cs

+ Recent posts