문제가 있는 링크
#17830: 이진수의 일상
이진수는 이진수를 사랑한다. 그의 일상은 하루 종일 두 개의 이진수를 생각하고 그 두 숫자의 곱을 “오늘의 이진수”로 선택하는 것입니다. 그런 다음 좋은 종이를 사서 “오늘의 이진수”라고 적으십시오.
www.acmicpc.net

문제
주어진 조건에 따라 이진수를 곱할 때 최대 자릿수와 최소 자릿수를 찾아야 합니다. 그러나 이진 곱셈이지만 실제로 곱셈을 하면 최대값이 \(2^{2,000,000}\)가 되므로 실제 곱셈을 할 수 없다. BigInteger로 계산해도 값이 너무 커서 타임아웃된다.
오늘의 이진수를 최대 자릿수로 만들기 위해서는 모든 ? 1 반대로 오늘의 이진수를 가장 작은 자리로 만들려면 모두 ? 0이 되십시오.
이 문제를 해결하려면 이진수의 속성을 사용해야 합니다. 이진수의 각 자릿수는 \(2^n\)이므로 \(2^m\)을 곱하면 전체 자릿수 \(n+m+1\)이 됩니다. 예: \(1111 \times 1000=1111000\). 따라서 두 이진수를 곱하여 구한 자릿수는 기본적으로 선행 0을 제외한 자릿수의 합 – 1입니다.
여기서 고려해야 할 두 가지 경우가 있습니다. \(B\)에 1이 여러 개 있는 경우와 없는 경우입니다. \(B\)에 1이 없는 경우는 \(B=0\), 즉 곱한 결과가 0이므로 자릿수는 반드시 1이 된다. ) 1이 여러 개 있고 \(A\)의 모든 비트가 1이므로 선행 0이 없는 숫자의 합입니다. 이 경우의 예는 \(1111\times 1??1\)입니다. 이 경우 결과는 \(1111000\)에 \(111100\), \(11110\), \(1111\) 중 하나 이상을 더한 값이며, 셋 중 하나를 더해도 자릿수는 1씩 증가합니다. .
자릿수를 구하는 방법을 알았으니 이제 수학만 하면 됩니다. 최대 자릿수를 찾으려면 1과 ?를 사용하십시오. 중간의 자릿수가 크면(=주어진 문자열 \(B\)에서 1과 ?의 첨자 중 작은 값) 1과 ?의 합을 기준으로 분기 처리한다. 실시. 최소 자릿수를 얻으면 ?를 무시하고 1의 수를 기준으로 분기 처리를 수행합니다.
암호
import java.util.StringTokenizer
fun main() = with(System.`in`.bufferedReader()) {
val bw = System.out.bufferedWriter()
repeat(readLine().toInt()) {
val st = StringTokenizer(readLine())
val n = st.nextToken().toInt()
val bin = st.nextToken()
val indexOfQ = bin.indexOf('?')
val indexOf1 = bin.indexOf('1')
var countQ = 0
var count1 = 0
for (c in bin) {
when (c) {
'1' -> count1++
'?' -> countQ++
}
}
val max = if (indexOfQ < 0 || indexOf1 < 0) n + (bin.length - maxOf(indexOfQ, indexOf1)) else n + (bin.length - minOf(indexOfQ, indexOf1))
val min = n + (bin.length - indexOf1)
bw.write(if (count1 + countQ == 0) "1 " else if (count1 + countQ == 1) "${max - 1} " else "$max ")
bw.write(if (count1 == 0) "1\n" else if (count1 == 1) "${min - 1}\n" else "$min\n")
}
bw.close()
}