그냥 하는 노트와 메모장

BOJ 2731 - 1379와 세제곱 본문

Solved problems

BOJ 2731 - 1379와 세제곱

coloredrabbit 2018. 1. 21. 21:02

조금 짜증나는 백트랙킹 문제였다. unsigned long long 범위를 벗어나지 않기 위해서는 곱셈과정을 직접 구현해야 한다. 그렇지 않으면 10자리 수에 대한 세제곱 수를 구할 때, 무조건 overflow가 발생한다.


기본 아이디어는 다음과 같다. 일의 자리에 대해서 생각을 해보자. 어떤 한자리 수 세제곱을 하면 숫자 k(0 <= k <= 9)에 대해 표를 만들어보자.


k

1

2

 k*k*k

1

8



따라서 greedy하게 맨 끝 숫자부터 시작하여 주어진 숫자를 만드면서 답을 만들어가면 된다. 문제 조건에 답은 무조건 있다고 하므로 안심하고 백트랙킹을 시행한다.



미리 10에 대해 제곱수를 계산해두고 이를 modular 연산, 곱셈 연산에 이용하여 시간을 아낀다. 수 0~9까지 하나씩 넣으면서 그 자리 수를 찾고 아니면 돌아와서 계산한다.



#include <cstdio>
using ll = unsigned long long;
int L;
ll ten[15], N, ans;

ll mul(ll a, ll b, ll md) {
	int apos, bpos = 0;
	ll ret = 0, sa, sb;
	while (b / ten[bpos]) {
		sb = b / ten[bpos];
		sb %= 10;
		apos = 0;
		while (bpos + apos <= md) {
			sa = a / ten[apos];
			sa %= 10;
			ret += sb*sa*ten[bpos + apos]%ten[md];
			ret %= ten[md];
			apos++;
		}
		bpos++;
	}
	
	return ret%ten[md];
}

bool back(int p, ll c) {
	if (p == L) {
		ans = c;
		return 1;
	}
	ll t, tt;
	for (ll i = 0; i < 10; i++) {
		tt = c + i*ten[p];
		t = mul(tt, tt, p + 1);
		t %= ten[p + 1];
		t = mul(t, tt, p + 1);
		t %= ten[p + 1];
		if (N%ten[p + 1] != t) continue;
		if (back(p + 1, c + i*ten[p])) return 1;
	}

	return 0;
}
int main() {
	int T;
	ll tmp;
	ten[0] = 1;
	for (int i = 1; i < 15; i++) ten[i] = ten[i - 1] * 10;
	scanf("%d", &T);
	while (T--) {
		ans = 0;
		scanf("%lld", &N);
		tmp = N, L = 0;
		while (tmp) {
			tmp /= 10, L++;
		}
		back(0, 0);
		printf("%lld\n", ans%ten[L]);
	}
	return 0;
}

'Solved problems' 카테고리의 다른 글

BOJ 2889 - 레스토랑 (RESTORAN)  (1) 2018.06.04
Codeforce Round 547 Div1. D - Mike and Fish  (0) 2018.05.29
BOJ 10978 - 기숙사 재배정  (0) 2018.01.18
BOJ 2485 - 가로수  (0) 2018.01.17
BOJ 2481 - 해밍 경로  (0) 2018.01.17
Comments