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

A에서 연속된 구간을 선택하여, 그 구간의 모든 원소에 대해 비트 OR을 수행했을 때 정확히 K가 되는 구간을 찾는 것입니다. 만약 여러 구간이 존재하면 아무거나 하나를 출력하고, 존재하지 않으면 1을 출력합니다.N과 목표 OR 값 K (1 ≤ N ≤ 200,000, 1 ≤ K ≤ 2^{30}-1)A의 N개의 정수 (1 ≤ A_i ≤ 2^{30}-1)s와 끝 인덱스 e를 출력 (1 기반 인덱스)1을 출력예제 입력 1:
5 7
8 1 2 5 9
예제 출력 1:
2 4
[1, 2, 5]의 비트 OR은 1 | 2 | 5 = 7입니다.예제 입력 2:
5 6
2 7 4 1 4
예제 출력 2:
-1
6이 되지 않습니다.이 문제는 연속된 구간의 비트 OR을 효율적으로 계산하고, 그 중 원하는 값 K가 되는 구간을 찾는 문제입니다. 배열의 크기가 최대 200,000이므로, 시간 복잡도가 O(N^2)인 브루트 포스 방식은 비효율적입니다. 대신, 동적 계획법(DP)을 사용하여 각 위치에서 가능한 비트 OR 결과를 추적하는 효율적인 방법을 사용합니다.
dp[i]: i번째 원소까지 고려했을 때, 구간의 비트 OR 결과가 특정 값인 경우를 추적합니다.i-1)에서 가능한 모든 OR 값에 현재 원소 A[i]를 OR하여 새로운 OR 값을 생성합니다.A[i] 자체로 새로운 구간을 시작할 수도 있습니다.2^{30}까지).K가 발생하면 해당 구간의 시작과 끝 인덱스를 기록합니다.prev_or를 초기화합니다.result를 (-1, -1)로 초기화합니다.current_or를 새롭게 계산한 OR 값과 그에 해당하는 시작 인덱스를 저장합니다.current_or에 K가 포함되어 있으면, 해당 구간의 시작과 현재 인덱스를 result에 저장합니다.result가 업데이트되었으면 해당 구간을 출력하고, 그렇지 않으면 1을 출력합니다.def find_subarray_with_or(N, K, A):
MOD = 10**9 + 9
prev_or = dict()
result = (-1, -1)
for i in range(N):
current_or = dict()
# 현재 원소 자체로 시작하는 구간
current_or[A[i]] = i
# 이전 단계에서 가능한 모든 OR 값에 현재 원소를 OR
for or_val, start_idx in prev_or.items():
new_or = or_val | A[i]
# 이미 기록된 OR 값이 있으면 더 이른 시작 인덱스를 유지
if new_or not in current_or or current_or[new_or] > start_idx:
current_or[new_or] = start_idx
# 현재 단계에서 OR 값이 K인 경우를 확인
if K in current_or:
s = current_or[K] + 1 # 1-based indexing
e = i + 1
result = (s, e)
break # 원하는 구간을 찾았으므로 종료
prev_or = current_or
return result if result != (-1, -1) else -1
def main():
import sys
import sys
input = sys.stdin.readline
N_K = input().split()
while len(N_K) < 2:
N_K += input().split()
N, K = map(int, N_K)
A = []
while len(A) < N:
A += list(map(int, input().split()))
res = find_subarray_with_or(N, K, A)
if res == -1:
print(-1)
else:
print(res[0], res[1])
if __name__ == "__main__":
main()
def find_subarray_with_or(N, K, A):
MOD = 10**9 + 9
prev_or = dict()
result = (-1, -1)
for i in range(N):
current_or = dict()
# 현재 원소 자체로 시작하는 구간
current_or[A[i]] = i
# 이전 단계에서 가능한 모든 OR 값에 현재 원소를 OR
for or_val, start_idx in prev_or.items():
new_or = or_val | A[i]
# 이미 기록된 OR 값이 있으면 더 이른 시작 인덱스를 유지
if new_or not in current_or or current_or[new_or] > start_idx:
current_or[new_or] = start_idx
# 현재 단계에서 OR 값이 K인 경우를 확인
if K in current_or:
s = current_or[K] + 1 # 1-based indexing
e = i + 1
result = (s, e)
break # 원하는 구간을 찾았으므로 종료
prev_or = current_or
return result if result != (-1, -1) else -1
prev_or: 이전 단계에서 가능한 모든 OR 값과 그에 해당하는 구간의 시작 인덱스를 저장하는 딕셔너리.current_or: 현재 단계에서 가능한 모든 OR 값과 그에 해당하는 구간의 시작 인덱스를 저장하는 딕셔너리.result: 조건을 만족하는 구간의 시작과 끝 인덱스를 저장하는 튜플. 초기값은 (-1, -1)로 설정하여, 조건을 만족하는 구간이 없을 경우 1을 출력할 수 있도록 합니다.현재 원소로 시작하는 구간 추가:
current_or[A[i]] = i
A[i] 자체로 시작하는 구간의 OR 값과 시작 인덱스를 current_or에 저장합니다.이전 단계 OR 값과 현재 원소의 OR 계산:
for or_val, start_idx in prev_or.items():
new_or = or_val | A[i]
if new_or not in current_or or current_or[new_or] > start_idx:
current_or[new_or] = start_idx
or_val에 현재 원소 A[i]를 OR하여 새로운 OR 값 new_or를 계산합니다.new_or가 이미 current_or에 존재하지 않거나, 더 이른 시작 인덱스를 가지고 있다면 업데이트합니다.조건 만족 여부 확인:
if K in current_or:
s = current_or[K] + 1 # 1-based indexing
e = i + 1
result = (s, e)
break
K인 경우를 확인합니다.s와 끝 인덱스 e를 계산하여 result에 저장하고, 더 이상의 탐색을 종료합니다.다음 단계로 이동:
prev_or = current_or
def main():
import sys
import sys
input = sys.stdin.readline
N_K = input().split()
while len(N_K) < 2:
N_K += input().split()
N, K = map(int, N_K)
A = []
while len(A) < N:
A += list(map(int, input().split()))
res = find_subarray_with_or(N, K, A)
if res == -1:
print(-1)
else:
print(res[0], res[1])
if __name__ == "__main__":
main()
N과 K를 입력받습니다.A의 N개의 원소를 입력받습니다.find_subarray_with_or 함수를 호출하여 결과를 얻습니다.1이면 1을 출력하고, 그렇지 않으면 구간의 시작과 끝 인덱스를 출력합니다.for i in range(N)O(N)for or_val, start_idx in prev_or.items()O(30) → O(1) (상수 시간)O(N) * O(1) = O(N)O(N)prev_or와 current_or 딕셔너리:O(30) → O(1) (상수 공간)result: 튜플O(1)O(1)prev_or와 current_or:O(1) 시간 내의 접근이 가능합니다.