Processing math: 85%

Codeforces

Codeforces #819

yujaa 2022. 9. 26. 16:55

A. Mainak and Array

길이 n의 배열 a가 주어진다.

배열의 [l,r] 구간을 선택, 원하는만큼 cyclically rotate하는 연산을 한 번 수행하여 얻을 수 있는 ana1의 최댓값을 구하는 문제이다.

 

다음과 같이 경우를 나눌 수 있다.

1) a1,an 미포함: ans=ana1

2) a1만 미포함: ans=max(a2,a3,...,an)a1

3) an만 미포함: ans=anmin(a1,a2,...,an1)

4) a1,an을 모두 포함: ans=max1in(ai1ai) (단, a0=an)

 

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 <bits/stdc++.h>
#define all(x) (x).begin(), (x).end()
using namespace std;
typedef long long ll;
typedef pair<intint> pii;
typedef tuple<intintint> tp;
 
int main(void) {
    cin.tie(NULL);
    ios::sync_with_stdio(false);
 
    int t; cin >> t;
    while (t--) {
        int n; cin >> n;
        vector<int> a(n+1);
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
        }
        a[0= a[n];
 
        int ans = a[n] - a[1];
        for (int i = 2; i <= n; i++) {
            ans = max(ans, a[i] - a[1]);
        }
        for (int i = 1; i <= n-1; i++) {
            ans = max(ans, a[n] - a[i]);
        }
        for (int i = 1; i <= n; i++) {
            ans = max(ans, a[i-1- a[i]);
        }
        cout << ans << '\n';
    }
    return 0;
}
cs

 

B. Mainak and Interesting Sequence

ap길이가 n인 배열이다.

 

배열 p의 원소 pi의 값은 다음과 같이 정의된다.

pi=the bitwise XOR of all elements in a which are strictly less than ai

 

배열 p의 모든 원소가 0일 때 배열 a를 interesting하다고 한다.

a1+a2+...+an=m을 만족하는 interesting한 배열 a를 찾는 문제이다. 단, ai>0이다.

 

배열 a에서 가장 작은 원소를 x, 그 다음 작은 원소를 y, 그 다음 작은 원소를 z, ...라고 하자.

x는 배열 a 안에 반드시 짝수개 존재해야 한다.

만약 홀수개 존재한다면 y 입장에서 봤을 때 p의 원소가 0이 아니게 된다.

y도 반드시 짝수개 존재해야 한다.

x를 모두 XOR한 값이 0이므로 y가 홀수개 존재하면 z 입장에서 p의 원소가 0이 아니게 된다.

같은 이유로 z, ...도 각각 짝수개 존재해야 한다.

단, 가장 큰 원소는 홀짝 개수 제한이 없다.

 

다음과 같이 경우를 나눌 수 있다.

1) n>m: NO

2) n이 홀수: 1, 1, ..., 1, 1, mn+1

3) n이 짝수:

  3-1) m이 짝수: 1, 1, ..., 1, mn+22, mn+22

  3-2) m이 홀수: NO

 

3-2 증명

n이 짝수, m이 홀수이면서 조건을 만족하는 배열 a가 존재한다고 가정하자.

m이 홀수이므로, 배열 a에는 어떤 홀수 x가 홀수개 존재해야 한다.

그런데 n이 짝수이므로 배열 a에 어떤 수 y가 홀수개 존재한다. (yx)

(위에서 증명한 정리에 의해) 이러한 배열은 존재할 수 없으므로 가정에 모순된다.

 

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
#include <bits/stdc++.h>
#define all(x) (x).begin(), (x).end()
using namespace std;
typedef long long ll;
typedef pair<intint> pii;
typedef tuple<intintint> tp;
 
int main(void) {
    cin.tie(NULL);
    ios::sync_with_stdio(false);
 
    int t; cin >> t;
    while (t--) {
        int n, m;
        cin >> n >> m;
        
        if (n > m) {
            cout << "No\n";
        }
        else {
            if (n % 2) {
                cout << "Yes\n";
                for (int i = 0; i < n-1; i++) {
                    cout << 1 << ' ';
                }
                cout << m - n + 1 << '\n';
            }
            else {
                if (m % 2) {
                    cout << "No\n";
                }
                else {
                    cout << "Yes\n";
                    for (int i = 0; i < n-2; i++) {
                        cout << 1 << ' ';
                    }
                    cout << (m - n + 2/ 2 << ' ';
                    cout << (m - n + 2/ 2 << '\n';
                }
            }
        }
    }
    return 0;
}
cs

 

C. Jatayu's Balanced Bracket Sequence

길이가 2n인 balanced bracket sequence s가 주어진다.

1i<j2n인 모든 i,j에 대해, s[i...j]가 balanced bracket sequence이면 ij를 잇는 간선을 그래프에 추가한다.

간선은 양방향이며 가중치가 붙지 않는다.

위 과정을 거쳐 만들어진 그래프의 component 개수를 구하는 문제이다.

 

i,j가 같은 component에 속하려면 다음 두 가지 조건을 만족해야 한다.

1) s[i],s[j]의 괄호 깊이가 같다.

2) ij 사이에 깊이가 더 낮은 괄호가 존재하지 않는다.

 

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 <bits/stdc++.h>
#define all(x) (x).begin(), (x).end()
using namespace std;
typedef long long ll;
typedef pair<intint> pii;
typedef tuple<intintint> tp;
 
int main(void) {
    cin.tie(NULL);
    ios::sync_with_stdio(false);
 
    int t; cin >> t;
    while (t--) {
        int n; cin >> n;
        string s; cin >> s;
        stack<int> st;
        vector<int> a;
        for (char ch: s) {
            if (ch == '(') {
                st.push(1);
                a.push_back(st.size());
            }
            else {
                st.pop();
            }
        }
        int ans = 1;
        for (int i = 1; i < (int)a.size(); i++) {
            if (a[i] > a[i-1]) ans++;
        }
        cout << ans << '\n';
    }
    return 0;
}
cs

 

D. Edge Split

n개의 정점과 m개의 간선으로 구성된 무방향, 가중치 없는 연결 그래프가 주어진다.

각 간선을 빨간색 또는 파란색 중 하나로 칠한다.

빨간 간선만 고려했을 때 component의 개수를 c1, 파란 간선만 고려했을 때 component의 개수를 c2라고 하자.

c1+c2의 최솟값을 구하는 문제이다.

 

mn+2 조건이 눈에 띈다. 스패닝 트리 느낌이 난다.

빨간 간선으로만 이뤄진 그래프를 R, 파란 간선으로만 이뤄진 그래프를 B라고 하자.

WLOG, R이 스패닝 트리일 때 정답이 되지 않을까? 정말 그런지 증명해보자.

 

증명

1. R에 cycle이 존재하는 경우

cycle에 포함된 어떤 간선 eR에서 B로 옮긴다.

이때 c1은 변하지 않고 c2는 최대 1만큼 감소한다.

 

2. R이 두 개 이상의 component로 구성된 경우

R의 서로 다른 component에 속해 있는 두 정점 u,v를 잇는 간선을 B에서 R로 옮긴다.

이때 c1은 1만큼 감소하고 c2는 최대 1만큼 증가한다.

 

두 행동 모두 최적해를 악화시키지 않는다는 것을 알 수 있다.

 

R을 스패닝 트리로 만들었으므로 c1=1이다.

이제 c2를 최소화해야 하는데, 남은 간선의 개수는 최소 0개에서 최대 3개이다.

B에 cycle이 생기는 경우만 조심하면 된다.

 

B에 포함된 간선이 uv,vw,wu라고 하자.

DFS spanning tree에 포함된 간선은 tree edge와 back edge로 나뉜다.

따라서, WLOG, u,vw의 조상이다.

w의 부모를 p라고 하자.

BvwRwp를 교환함으로써 문제를 해결할 수 있다.

 

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
#include <bits/stdc++.h>
#define all(x) (x).begin(), (x).end()
using namespace std;
typedef long long ll;
typedef pair<intint> pii;
typedef tuple<intintint> tp;
 
int n, m;
vector<int> par;
vector<int> depth;
vector<vector<pii> > adj;
vector<int> ans;
 
void dfs(int u, int p, int d) {
    par[u] = p;
    depth[u] = d;
    for (auto [v, idx]: adj[u]) {
        if (v != p && depth[v] == -1) {
            dfs(v, u, d+1);
            ans[idx] = 1;
        }
    }
}
 
int main(void) {
    cin.tie(NULL);
    ios::sync_with_stdio(false);
 
    int t; cin >> t;
    while (t--) {
        cin >> n >> m;
        par.clear(); par.resize(n+1);
        depth.clear(); depth.resize(n+1-1);
        adj.clear(); adj.resize(n+1);
        ans.clear(); ans.resize(m);
 
        for (int i = 0; i < m; i++) {
            int u, v;
            cin >> u >> v;
            adj[u].push_back({v, i});
            adj[v].push_back({u, i});
        }
 
        dfs(100);
 
        if (m == n + 2) {
            vector<int> vertex;
            for (int i = 1; i <= n; i++) {
                for (auto [j, idx]: adj[i]) {
                    if (ans[idx] == 0) {
                        vertex.push_back(i);
                        vertex.push_back(j);
                    }
                }
            }
            sort(all(vertex));
            vertex.erase(unique(all(vertex)), vertex.end());
 
            if (vertex.size() == 3) {
                int w = vertex[0];
                int v = vertex[1];
                if (depth[w] < depth[v]) swap(w, v);
 
                int idx1, idx2;
                for (auto [i, idx]: adj[w]) {
                    if (i == v) idx1 = idx;
                    if (i == par[w]) idx2 = idx;
                }
                swap(ans[idx1], ans[idx2]);
            }
        }
 
        for (int i: ans) {
            cout << i;
        }
        cout << '\n';
    }
    return 0;
}
cs

 

'Codeforces' 카테고리의 다른 글

Codeforces #763  (0) 2022.01.02
Codeforces Educational #120  (0) 2022.01.02
Codeforces Global #18  (0) 2021.12.26
Codeforces Educational #82  (0) 2021.12.26
Codeforces #619  (0) 2021.12.23