Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- (() => {
- const { floor, sqrt } = Math;
- function clamp(min, n, max) {
- return Math.max(min, Math.min(max, n));
- }
- function inRange(min, n, max) {
- return clamp(min, n, max) === n;
- }
- function range(start, end) {
- return start > end ? [] : Array.from(new Array(end - start + 1)).map((_unused, i) => i + start);
- }
- function isDivisible(n, by) {
- return floor(n / by) * by === n;
- }
- const RANGE_MIN = 2;
- const RANGE_MAX = 50;
- const SUM_MIN = RANGE_MIN + (RANGE_MIN + 1);
- const SUM_MAX = RANGE_MAX + (RANGE_MAX - 1);
- const MUL_MIN = RANGE_MIN * (RANGE_MIN + 1);
- const MUL_MAX = RANGE_MAX * (RANGE_MAX - 1);
- function possibleSetWhenSum(sum) {
- return range(RANGE_MIN, floor(clamp(SUM_MIN, sum, SUM_MAX) / 2))
- .map((i) => [i, sum - i])
- .filter(([n, m]) => n < m && inRange(RANGE_MIN, n, RANGE_MAX) && inRange(RANGE_MIN, m, RANGE_MAX));
- }
- function possibleSetWhenMul(mul) {
- return range(floor(sqrt(MUL_MIN)), floor(sqrt(clamp(MUL_MIN, mul, MUL_MAX))))
- .filter((i) => isDivisible(mul, i))
- .map((i) => [i, mul / i])
- .filter(([n, m]) => n < m && inRange(RANGE_MIN, n, RANGE_MAX) && inRange(RANGE_MIN, m, RANGE_MAX));
- }
- function possibleSumWhenMul(mul) {
- return possibleSetWhenMul(mul).map(([n, m]) => n + m);
- }
- function possibleMulWhenSum(sum) {
- return possibleSetWhenSum(sum).map(([n, m]) => n * m);
- }
- function isTrivialSum(sum, mulWhitelist = possibleMulWhenSum(sum)) {
- return possibleSetWhenSum(sum)
- .filter(([n, m]) => mulWhitelist.includes(n * m))
- .length <= 1;
- }
- function isTrivialMul(mul, sumWhitelist = possibleSumWhenMul(mul)) {
- return possibleSetWhenMul(mul)
- .filter(([n, m]) => sumWhitelist.includes(n + m))
- .length <= 1;
- }
- function solution() {
- // S가 아는 두 수의 합 후보
- const possibleSum =
- // 합으로 주어질 수 있는 모든 수 중에
- range(SUM_MIN, SUM_MAX)
- .filter((sum) => {
- // S는 정답을 모르므로 우선 S가 답을 아는 경우 제외
- if (isTrivialSum(sum)) return false;
- // 합이 sum일 때 P가 아는 수 후보
- const possibleMul = possibleMulWhenSum(sum);
- // 그 중 하나의 경우라도 P가 답을 알 수 있다면
- const PMightKnow = possibleMul.some((mul) => isTrivialMul(mul));
- // S는 P가 답을 모른다는 것을 알 수 없었을 것임
- return !PMightKnow;
- });
- // P가 아는 두 수의 곱 후보
- const possibleMul =
- // P가 합이 possibleSum 중 하나라는 것을 알아도 정답을 모르려면
- possibleSum.map(possibleMulWhenSum).flat(1) // 가능한 모든 곱
- .sort().filter((_unused, i, a) => a[i] != a[i - 1]) // 중복 제거
- // 하지만 P는 S가 정답을 모른다는 것을 알고 있음
- .filter((mul) => !isTrivialMul(mul, possibleSum));
- // S가 예상할 수 있는, P가 아는 가능한 정답 후보
- const possibleSet =
- possibleMul.map(possibleSetWhenMul).flat(1) // 가능한 모든 경우
- .filter(([n, m]) => possibleSum.includes(n + m)); // 아닌 경우 제거
- // 실제로 S가 아는 두 수의 합
- const realSum =
- possibleSum // S가 아는 두 수의 합 후보 중에서
- .filter((sum) => // S가 정답을 알겠다고 했으니 가능한 경우가 1개여야 함
- possibleSet.filter(([n, m]) => n + m == sum).length === 1
- );
- if (realSum.length !== 1) throw new Error('문제 에러 아님???');
- return possibleSet.filter(([n, m]) => n + m == realSum[0])[0];
- }
- return solution();
- })()
Advertisement
Add Comment
Please, Sign In to add comment