본문 바로가기
카테고리 없음

[백준 27172] 수 나누기 게임 (C++)

by fortissimo 2024. 3. 4.

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

 

27172번: 수 나누기 게임

《보드게임컵》을 준비하다 지친 은하는 보드게임컵 참가자들을 경기장에 몰아넣고 결투를 시키는 게임 《수 나누기 게임》을 만들었습니다. 《수 나누기 게임》의 규칙은 다음과 같습니다.

www.acmicpc.net

문제


《보드게임컵》을 준비하다 지친 은하는 보드게임컵 참가자들을 경기장에 몰아넣고 결투를 시키는 게임 《수 나누기 게임》을 만들었습니다.

《수 나누기 게임》의 규칙은 다음과 같습니다.

  • 게임을 시작하기 전 각 플레이어는 부터  사이의 수가 적힌 서로 다른 카드를 잘 섞은 뒤 한 장씩 나눠 가집니다.
  • 매 턴마다 플레이어는 다른 플레이어와 한 번씩 결투를 합니다.
  • 결투는 서로의 카드를 보여주는 방식으로 진행되며, 플레이어의 카드에 적힌 수로 다른 플레이어의 카드에 적힌 수를 나눴을 때, 나머지가 이면 승리합니다. 플레이어의 카드에 적힌 수가 다른 플레이어의 카드에 적힌 수로 나누어 떨어지면 패배합니다. 둘 다 아니라면 무승부입니다.
  • 승리한 플레이어는 점을 획득하고, 패배한 플레이어는 점을 잃습니다. 무승부인 경우 점수의 변화가 없습니다.
  • 본인을 제외한 다른 모든 플레이어와 정확히 한 번씩 결투를 하고 나면 게임이 종료됩니다.

《수 나누기 게임》의 결과를 가지고 한별이와 내기를 하던 은하는 게임이 종료되기 전에 모든 플레이어의 점수를 미리 알 수 있을지 궁금해졌습니다. 은하를 위해 각 플레이어가 가지고 있는 카드에 적힌 수가 주어졌을 때, 게임이 종료된 후의 모든 플레이어의 점수를 구해주세요.

 

입력


첫 번째 줄에 플레이어의 수 이 주어집니다.

두 번째 줄에 첫 번째 플레이어부터 번째 플레이어까지 각 플레이어가 가지고 있는 카드에 적힌 정수 , ⋯, 이 공백으로 구분되어 주어집니다.

출력


첫 번째 플레이어부터 번째 플레이어까지 게임이 종료됐을 때의 각 플레이어의 점수를 공백으로 구분하여 출력해주세요.

 

제한


  •  2 ≤ N ≤ 100,000 
  • 모든 1 ≤ i ≤ N에 대해 1 ≤  xi  ≤1000000입니다.
  • 모든 1 ≤ i < j ≤ N에 대해 xi ≠ xj입니다. 즉, 어떤 수도 에서 두 번 이상 등장하지 않습니다.

문제 풀이


각 플레이어의 카드에 적힌 수에 대해 약수를 찾는 문제였다.

각 플레이어의 카드에 적힌 수 xi에 대해 에라토스테네스의 체와 비슷한 방법으로 1부터 xi의 제곱근까지 반복문을 돌린다. 만약 xi가 해당 수 j로 나누어 떨어진다면 약수이며, xi / j 역시 약수이다. 입력 받은 전체 배열에 j와 xi / j가 존재하는지 찾는다. 있다면 점수를 기록하는 points 배열에서 해당 값을 가지는 index의 value를 1 증가시키고, i번째 index의 value를 1 감소시킨다. xi가 제곱수일 때 j와 xi / j가 같은 수가 되므로 중복해서 점수를 기록하지 않도록 주의가 필요하다.

 

아래는 코드.

더보기
#include <iostream>
#include <map>
#include <cmath>
using namespace std;

int main()
{
	cin.tie(NULL);
	ios::sync_with_stdio(false);

	int N;
	int cardNum;
	cin >> N;
	map<int, int> m;
	map<int, int>::iterator it;
	int* cardNums = new int[N];
	int* points = new int[N];
	for (int i = 0; i < N; i++)
	{
		cin >> cardNum;
		m.insert({ cardNum, i });
		cardNums[i] = cardNum;
		points[i] = 0;
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 1; j <= sqrt(cardNums[i]); j++)
		{
			if (cardNums[i] % j == 0)
			{
				it = m.find(j);
				if (it != m.end())
				{
					points[i]--;
					points[it->second]++;
				}
				int next = cardNums[i] / j;
				if (j != next)
				{
					it = m.find(next);
					if (it != m.end())
					{
						points[i]--;
						points[it->second]++;
					}
				}
			}
		}
	}
	for (int i = 0; i < N; i++)
	{
		cout << points[i] << " ";
	}
	return 0;
}