본문 바로가기

문제풀이/백준

ALOHA 여름방학 고급반 1주차

A. https://www.acmicpc.net/problem/27739

 

제곱이 도는 제한이니 길이 K인 구간을 고르는 경우 $O(N)$개를 각각 $O(N)$ 내지 $O(N\log N)$ 정도에 풀면 되고, 고른 구간을 정렬하고 좌표압축 비스무리하게 하면 풀 수 있다. 고려해야 하는 케이스는 왼쪽으로 쭉 늘리기 / 오른쪽으로 쭉 늘리기 / (가능하다면) 구간 전체 다 쓰기 세 가지인데, 처음에는 첫 두 가지 제대로 생각 못해서 좀 절었다. 구현이 좀 귀찮앗음..

 

더보기
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
#include <bits/stdc++.h>
using namespace std;
 
int N, K, A[2020];
int main() {
    cin.tie(nullptr)->sync_with_stdio(0);
 
    cin >> N >> K;
    for (int i = 1; i <= N; i++cin >> A[i];
    int ans = 0;
    for (int l = 1, r = K; r <= N; l++, r++){
        vector<int> B;
        for (int i = l; i <= r; i++) B.push_back(A[i]);
        sort(B.begin(), B.end());
        B.erase(unique(B.begin(), B.end()), B.end());
        int nl = l-1, nr = r+1, bef = 1e9;
        for (; nl and A[nl] < bef; bef = A[nl--]);
        bef = 0;
        for (; nr <= N and A[nr] > bef; bef = A[nr++]);
        int now = B.size();
        if (l > 1) now = max<int>(now, B.end() - upper_bound(B.begin(), B.end(), A[l-1]) + l-nl-1);
        if (r < N) now = max<int>(now, lower_bound(B.begin(), B.end(), A[r+1]) - B.begin() + nr-r-1);
        if (1 < l and r < N and A[l-1< B[0] and B.back() < A[r+1]) now = nr - nl - 1;
        ans = max(ans, now);
    }
    cout << ans;
}
cs

 

B. https://www.acmicpc.net/problem/30484

 

문자열 자체의 inversion / 반복되어 생기는 inversion을 고려하면 식 정리가 깔끔하게 된다. 알파벳 문자열이라 inversion을 단순하게 구해도 된다. 오버플로 처리가 쪼금 귀찮아 보여서 파이썬 썼다.

 

더보기
1
2
3
4
5
6
7
8
9
10
11
12
= input().strip()
= int(input())
cnt = [0]*30
inv = aa = 0
for c in s:
    for i in range(ord(c)+1, ord('z')+1):
        inv += cnt[i-ord('a')]
    cnt[ord(c)-ord('a')] += 1
for c in s:
    for i in range(ord(c)+1, ord('z')+1):
        aa += cnt[i-ord('a')]
print((inv * N + N*(N-1)//2 * aa) % 1000000007)
cs

 

C. https://www.acmicpc.net/problem/31572

 

풀기 싫게 생긴 데 비해 할 수 있는 일이 몇 가지 없어서 풀 만 했다.

 

count_pair를 $\lfloor \frac{N}{2} \rfloor +1$번, find_character는 1번만 쓸 수 있다. 팰린드롬인지 판별하려면 적어도 $\lfloor \frac{N}{2} \rfloor$개의 숫자 쌍을 비교해야 하니, 어떻게든 count_pair로 비교를 수행해야 한다고 유추할 수 있다. count_pair의 인자로 비교할 두 위치 $i$, $N-i-1$과 임의의 다른 위치 $x$를 넘겼다고 생각해 보자. $S_x$와 관계 없이 반환값이 $3$이라면 $S_i = S_{N-i-1}$이고, $0$이라면 $S_i \neq S_{N-i-1}$이니 반환값이 $1$일 때만 잘 처리하면 된다. 이를 위해 find_character를 잘 활용해야 할 것이다.

 

find_character는 수 하나와 다른 여러 수들을 비교하므로, count_pair에서 넘길 다른 위치 $x$를 모두 통일하자. 사고의 편의를 위해 수열의 길이가 홀수인 상황을 먼저 생각하면, 비교할 필요 없는 수열의 가운데 인덱스를 $x$로 쓸 수 있다. count_pair의 반환값이 $1$인 모든 $(i, N-i-1)$ 쌍에 대해 $S_i \neq S_x$이고 $S_{N-i-1} \neq S_x$라면 $S_i = S_{N-i-1}$이므로, find_character를 통해 반환값이 $1$인 쌍을 한꺼번에 조사하여 팰린드롬 여부를 판단할 수 있다.

 

수열의 길이가 짝수라면 $S_x = S_{N-x-1}$인지도 판단해야 한다. $(x, N-x-1)$ 쌍을 제외한 다른 쌍들은 같은 방법으로 조사할 수 있으며, count_pair를 2번 더 사용할 수 있다. 조사를 마친 상태에서 $x$과 $N-x-1$이 아닌 임의의 인덱스 $t$를 골랐을 때 $S_t = S_{N-t-1}$를 만족하며, $S_t$와 $S_x$가 같은지 여부도 count_pair의 반환값을 통해 알고 있다. 따라서 $S_t$와 $S_x$가 같을 때와 다를 때로 케이스를 나눠 count_pair를 적절히 쓰면 $S_x$와 $S_{N-x-1}$ 또한 비교할 수 있어 문제를 풀 수 있다. 

 

더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <vector>
 
extern int count_pair(intintint);
extern int find_character(intstd::vector<int>);
 
int guess_palindromicity(int N) {
    using namespace std;
    vector<int> v;
    for (int i = 1; i < N/2; i++){
        int r = count_pair(0, i, N-i-1);
        if (r == 0return 0;
        else if (r == 1) v.push_back(i), v.push_back(N-i-1);
    }
    if (v.size()){
        if (find_character(0, v)) return 0;
        return count_pair(v[0], 0, N-1== 1 and count_pair(v[0], N-v[0]-1, N-1== 1;
    }
    else
        return count_pair(0, N-11== 3;
}
cs

 

D. https://www.acmicpc.net/problem/12430

 

딱 봐도 그리디한 조건으로 정렬해서 냅색 돌리면 될 것처럼 생겼는데.. 조건 찾는 데 시간이 오래 걸렸다. P+S 오름차순으로 정렬하면 exchange argument 느낌으로 최적해가 될 것 같다는 믿음을 가지고 짰다. 

 

이 문제처럼 가능/불가능을 따지는 냅색은 뒤부터 업데이트하면 공간을 줄일 수 있고, 비트셋으로 최적화할 수 있다는 사실은 잘 알려져 있다. T <= 100인데 $\sum N$ 제한이 없어 비트셋 써야 하나 싶었는데 없어도 빨리 잘 돌아간다. 아마 최대 데이터가 안 들어있지 않을까?

 

더보기
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
#include <bits/stdc++.h>
using namespace std;
using pii = pair<int,int>;
 
int N, dp[101010];
void solve(){
    cin >> N;
    memset(dp, 0sizeof dp);
    vector<pii> v(N);
    for (auto&[p,s] : v) cin >> p >> s;
    sort(v.begin(), v.end(), [](pii a, pii b){
        return a.first+a.second < b.first+b.second;
    });
    dp[0= 1;
    for (auto[p,s] : v){
        for (int i = p+s; i >= s; i--)
            dp[i] |= dp[i-s];
    }
    for (int i = 101000;;i--){
        if (dp[i]){
            cout << i << '\n';
            return;
        }
    }
}
 
int main() {
    cin.tie(nullptr)->sync_with_stdio(0);
 
    int t;
    cin >> t;
    for (int i = 1; i <= t; i++){
        cout << "Case #" << i << ": ";
        solve();
    }
}
cs

 

E. https://www.acmicpc.net/problem/23096

 

아무생각안든다. 너무어려움

'문제풀이 > 백준' 카테고리의 다른 글

백준 20297 Confuzzle  (2) 2025.09.06
ALOHA 여름방학 고급반 3주차  (0) 2025.07.26
백준 33722 [B] 이진 매칭  (0) 2025.06.06
백준 33628 Connect the GSHS  (2) 2025.05.17
백준 25432 각성제  (1) 2025.05.05