https://www.acmicpc.net/problem/2830
2830번: 행성 X3
상근이는 초등학교 졸업 여행으로 외계 행성 X3에 방문했었다. 이 행성에 사는 사람들의 이름은 모두 자연수이다. 행성의 거주민은 모두 서로를 알고 있다. 두 X3인은 그들의 친밀도를 자신의 이
www.acmicpc.net
원리만 알면 나름 간단해지는 문제였다!
정말 두 개씩 확인하면서 모든 경우의 수를 합해주면 시간 초과가 뜬다!
아래처럼..!
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int[] arr= new int[n];
for(int i = 0 ; i<n ; i++){
arr[i] = scan.nextInt();
}
int count = 0;
for(int i=0; i <arr.length -1 ;i++){
for(int j=i+1 ; j<arr.length ; j++){
count+=((arr[i]|arr[j]) & ~(arr[i]&arr[j])); // ^ 연산자가 있는데 생각이 안났다.
}
}
System.out.print(count);
}
}
위의 코드는 처음에 푼 방식.. 적으면서도 시간초과 뜰 것 같았는데 역시나다.
그래서 다시 생각해낸 방식이 아래의 방식이다.
한꺼번에 할 수 있는 방법이 없을까.. 고민하다
각 자리의 수에서 1과0을 뽑을 경우의 수만 알면 되는 것이었다.
왜냐하면 서로 달라야 즉 1과 0이어야 1이 되니까 말이다!
그리하여 같은 자리에서 1의 개수와 0의 개수를 곱해주면
두개씩 엮어서 친밀도를 구했을 때의 해당자리의 1의 개수를 알아낼 수 있다..(말이 어렵다..)
다만 2진수 인점을 고려하여 2의 0승 2의 1승 ... 곱해주는 것을 잊지말자.
혹시, 이해가 안되는 분들을 위해 조금 더 설명하자면
각 자리의 수는 다른 자리의 수에 영향을 끼치지 않습니다.
각 자리 수만 2개씩 비교를 해서 답을 내니까요
그래서 각자리수의 1몇개와 0몇개에서 1과0 두개(순서x) 뽑을 경우의 수를 구한다고 생각해주시면 됩니다.
1이 올 확률 = 1의 개수
0이 올 확률 = 0의 개수
각 자리수는 1과 0밖에 없으므로
1의 개수 + 0의 개수 = 전체의 개수
즉 1의 개수는 = 전체의 개수 - 0의 개수
0의 개수는 = 전체의 개수 - 1의 개수
다시 말해서 각자리수의 1몇개와 0몇개에서 1과0을 뽑을 경우의 수를 구하려면
1의 개수 * 0의 개수 입니다.
= 1의 개수 * (전체개수 - 0의 개수)
그리고 마지막으로 각 자리수는 이진수를 나타내고 있으니
각 자리수에 맞는 2^n 을 곱해주어 다 더하면 값이 나옵니다!
대충 다른 예를 들자면 파란색 공 3개와 빨간색공 2개에서
빨간색공하나와 파란색공 하나를 뽑을 확률은
3*2 인것입니다!
추가로 왜 1하나 0하나 경우의 수를 구해주냐면
두개가 다를때가 1이 되주는데
두개가 다를때는 1과 0밖에 없기 때문입니다!
즉 1과 0이 올때만 1이 되는데
해당 1의 개수를 세어주는게 목표기 때문에 1과 0이 올 때의 경우의 수만 생각하면 됩니다!
아래는 참고 그림
사실 이 방법을 알고나서도 안되서 한참을 걸렸다..
계속 반례가 뭘지...
내가 로직을 잘 못 짠건가... 해서 계속 쳐다봤는데 알고보니
위의 코드가 되기전에 count1의 변수가 int타입이었다.
해당 count1을 이용하여 answer을 계산해주었기 때문에 int로 자동 형변환이 되어 잘못된 값이 나왔던 것이다 ㅠㅠㅠ
3%에서 계속 막히시는 분들은 int타입의 범위를 생각해주세요 ㅠㅠ
코드는 아래와 같습니다.
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int[] arr= new int[n];
int max = 0;
for(int i = 0 ; i<n ; i++){
arr[i] = Integer.parseInt(br.readLine());
max = Math.max(arr[i], max);
}
long ss = 1;
long answer = 0;
while(max != 0){
long count1 = 0;
for(int i=0; i <arr.length ;i++){
if(arr[i] == 0)continue;
if(arr[i]%2 == 1) count1++;
arr[i] /= 2;
}
answer += ((count1 * (n - count1)) * ss);
// answer += (((long)count1 * (n - count1)) * (long)ss);
ss = ss << 1;
max/=2;
}
System.out.print(answer);
}
}
'Coding test > Baekjoon' 카테고리의 다른 글
[백준][JAVA] 11725: 트리의 부모 찾기 (0) | 2023.08.26 |
---|---|
[백준][JAVA] 1912번: 연속합 (0) | 2023.08.18 |
[백준][JAVA] 9012번: 괄호 (0) | 2023.08.14 |
[백준][JAVA] 10807번: 개수 세기 (0) | 2023.08.14 |
[백준][JAVA] 1158번: 요세푸스 문제 (0) | 2023.08.12 |