코드포스에 너무 어려움을 느껴 앞으로 editorial를 보고 공부하여 블로그에 정리하고자 한다..
(Div2 2솔까지는 할만한데 3솔부터 못해먹겠다.)
A - min max swap [Solved!]
두 배열 a1,a2,...,ana1,a2,...,an과 b1,b2,...,bnb1,b2,...,bn이 주어졌을 때 같은 인덱스들을 여러번 적절히 바꾸어 만들어진 새로운 두 배열을 만든다. 만들어진 각 배열의 최댓값을 곱했을 때 가능한 최솟값을 구하는 문제이다.
ai,biai,bi를 비교하면서 두 수중 작은 값을 aiai, 큰 값을 bibi에 넣으면 최적해가 구해진다.
B - Fun with Even Subarrays [Solved!]
배열이 주어졌을 때 적당한 범위 al,al+1,...,aral,al+1,...,ar을 정해서 k=r−l+1k=r−l+1이라 할 때 ai−k=aiai−k=ai라 하자.(l≤i≤rl≤i≤r) 이 연산을 유한번 반복하면 모든 배열의 원소가 같아지는데 그 횟수의 최솟값을 구하는 문제이다.
배열은 앞에 있는 값을 뒤에 있는 값으로 대체하는 문제이므로 맨 뒤에 있는 값은 변할 수 없다. 결국 최종 배열은 맨 뒤에 있는 값만 가진 배열이 나올것이다. 그럼 뒤에서부터 같은 값이 얼마나 연속해서 있는지만 구하면 된다.
예를 들어 배열이 [4,2,1,3,3][4,2,1,3,3]이라고 하자.
마지막 값은 3이고 연속해서 2개가 있다.
이를 연산 처리하면 [4,3,3,3,3][4,3,3,3,3]이 된다.
같은 방법을 한번 더 사용하면 마지막 값이 연속해서 4개가 있으므로 [3,3,3,3,3][3,3,3,3,3]이 되어 2번만에 배열의 값을 같게 만들 수 있다.
C - And Matching
nn은 2의 제곱수이고 (0,1,...,n−1)(0,1,...,n−1)인 배열이 있을 때 이를 적당히 두개씩 짝지으면 n2n2개의 집합이 만들어진다. ((a1,b1),(a2,b2),...,(an2,bn2))((a1,b1),(a2,b2),...,(an2,bn2)) 이때 ∑n2i=1ai&bi=k∑n2i=1ai&bi=k를 만들 수 있는지 묻는 문제이다.
내가 몰랐던 비트마스킹 기법을 사용한다. 우선 2=1022=102이고 ~2=0122=012인데 4자리 not연산을 하려면 2⊕15=1101(2)2⊕15=1101(2)가 된다. 이를 일반화하면 aa가 있고 nn자리 not연산을 하려면 a⊕(2n−1)a⊕(2n−1)을 하면 된다. (2n−1=11...122n−1=11...12이기때문)
또한 a&a&~a=0a=0임은 자명하다. (근데 난 이것도 몰랐다. 이산수학을 들어야 하는 이유)
* Case 1) k=0k=0
∑n2x=0x&∑n2x=0x&~xx로 구성하면 00이 나온다.
* Case 2) 0<k<n−10<k<n−1
k&(n−1)=kk&(n−1)=k 이고 ~k&0=0k&0=0이니까 남은 수 0<x<n2,x≠k,0<x<n2,x≠k,~kk에 대해 (x,(x,~x)x)로 구성하면 kk 가 나온다.
* Case 3) k=n−1k=n−1
이것도 2와 비슷하게 하면 되는데 n−1&n−1n−1&n−1이 안되기 때문에 n−1&n−2n−1&n−2를 하고 11을 찾자. 아무 홀수나 잡아도 되지만 가장 무난한 n−3n−3을 고르면 n−3&1=1n−3&1=1이 나온다. 그 후 (0,2)(0,2)을 구성하고 남은 수들에 대해 (x,(x,~x)x)로 짝지으면 된다.
여기서 n=4n=4일때는 n−3&1n−3&1을 할 수 없으므로 해가 존재하지 않는다.
D - Range and Partition
배열이 주어지고 그 배열을 다음 조건에 맞게 정확히 kk개의 부분배열을 만든다.
- 각 부분배열은 원래 배열에서 연속한 일부분이어야 한다.
- 원래 배열의 각 원소는 부분 배열중 하나에만 존재한다. (분할한다는 뜻인듯)
- 각 부분배열에서 [x,y][x,y]구간 안에 있는 원소 수가 구간 밖의 원소 수보다 크다.
이때 y−xy−x를 최소화하는 방법을 구하는 것이 문제이다.
굉장히 기발한 방법으로 해결한다.
우선 구간 [x,y][x,y]를 정하고 새로운 배열 bb를 정의하는데 x≤ai≤yx≤ai≤y 이면 bi=1bi=1이고 그 외에는 bi=−1bi=−1로 정의한다. (이런 발상이 놀라웠다.)
그리고 bb에 대한 부분합 psumpsum을 구한다.
만약 전체 합 psumn≥kpsumn≥k라면 조건에 만족하는 kk개의 배열을 만들 수 있으므로 1<x<k1<x<k에 대해 처음으로 psumi=xpsumi=x일 때마다 분할하면 된다. 예를들어 psum=[1,2,1,2,3,4],k=3psum=[1,2,1,2,3,4],k=3일 때 [1],[2],[1,2,3,4][1],[2],[1,2,3,4]로 분할하면 정답이 된다.
정답을 구하기 위해 구간 [x,y][x,y]를 구하는 과정은 다음과 같다.
psumn=∑ni=1bi=∑ni=1(−1+2⋅[x≤ai≤y])≥kpsumn=∑ni=1bi=∑ni=1(−1+2⋅[x≤ai≤y])≥k
→∑ni=1[x≤ai≤y]≥⌈k+n2⌉→∑ni=1[x≤ai≤y]≥⌈k+n2⌉
등호일 때 최소가 되고 원래 배열을 정렬을 해서 AA배열을 얻었을 때 Ai+⌈k+n2⌉−1−AiAi+⌈k+n2⌉−1−Ai의 최솟값을 구하면 된다.
E - Paint the Middle
???
F - Flipping Range
???
코드포스는 배열을 적당히 조작하는걸 좋아하는것 같다.
'프로그래밍 > 알고리즘' 카테고리의 다른 글
[알고리즘] Codeforces Round #769 (Div. 2) (0) | 2022.01.31 |
---|---|
[알고리즘] 2022 중앙대학교 CHAC (0) | 2022.01.30 |
[알고리즘] 이분탐색 (0) | 2021.12.23 |
[알고리즘] 알고리즘 문제를 풀 때 알면 좋은것들 (0) | 2021.12.05 |
[알고리즘] 모듈러 연산과 페르마의 소정리 (0) | 2021.12.02 |