요약 : 코딩을 못해도 시간을 박으면 누구나 풀 수 있다. 근성으로 가능한 플레 I 문제다! 근데 오래 걸린다.
완전 수학 문제였는데 예제 입력과 출력이 잘 나와 있어서 풀기까지 시간은 많이 걸렸지만 틀렸습니다를 받진 않았다.
교양 시간에 풀기 시작했는데 중간에 너무 많은 정보와 가정들이 머릿속에서 뒤엉켜서 뇌정지가 와버렸다.
관찰한 특징을 잘 솎아내서 정제된 풀이과정으로 만드는 작업이 심히 어려웠던 문제가 되겠다.
가 1,000,000까지밖에 되지 않아 완전탐색으로도 풀릴까 했지만 는 까지 올라간다는 사실을 깨닫고 절망했다.
먼저 인 가 존재하기 위한 조건을 알아보자.
참고로 는 이다.
= 일 때, 이다.
즉, 의 모든 자릿수에 대해 같은 숫자가 에 존재한다. (너무 당연하다) 그러므로 그 숫자끼리 묶을 수 있다.
여기서 눈치챘겠지만 맨 앞의 항과 맨 뒤의 항은 으로 묶을 수 있다. 2번째 항과 마지막에서 2번째 항도 그러하다. 이런 식으로 식을 정리하면 다음과 같이 나온다.
이제 형태에 주목하자. 이 형태의 식들은 하나의 공통점이 있는데, 바로 로 나누어 떨어진다는 점이다. 그래서 는 항상 의 배수가 된다.
여기까지 알아낸 사실은 다음과 같다.
이제 에 대해서 생각해 보자.
아까 들었던 예시인 에 대해 는 다음과 같다.
규칙성이 보이지 않는가?
항이 오른쪽으로 갈 수록 111111 => 11110 => 1100 으로 중요해보이는 숫자가 점점 줄어들고 있다.
세로로 한번 보자.
......
...
마치 1이 탑처럼 쌓인 형태가 된다.
만약 저 을 몰라도 저 자리에 이 들어간다는 사실을 충분히 유추할 수 있을까?
가능하다. 왜냐하면 우리는 이미 값을 알고 있기 때문이다.
일 때, 항만 가장 마지막 자릿수에 영향을 미치고, 그 부분을 계산해서 제하고 나면 항만 마지막에서 두 번째 자릿수에 영향을 미친다.
이런식으로 반복해나가면 값이 들어가야 한다는 사실을 알 수 있다.
정리
가 1자리 수일 때, 는 존재하지 않는다.
가 2자리 수일 때, 형태다.
가 3자리 수일 때, 형태다.
가 4자리 수일 때, 형태다.
가 5자리 수일 때, 형태다.
가 6자리 수일 때, 형태다.
가 13자리 수일 때, 형태다.
이미 13자리 수에서 가 표현 가능한 최솟값은 1,000,000을 넘어갔다. 의 최댓값이 1,000,000이므로 여기까지만 탐색해도 충분하다.
에 대한 가 n자리 수인지 확인하는 방법은 위에서 설명한대로 저 를 표현하는 수식으로 입력된 가 표현되는지 체크해 보면 된다.
탐색해야 할 분기가 13개밖에 안 되므로 그냥 하드코딩해도 되고, 조금 다듬어서 똑똑하게 풀어도 된다.
저 식에서 등의 해를 구했다면 거기서 파생되는 는 하나가 아니라 여러 개가 나오는데, 그 중 최솟값이므로 등이 양수라면 으로 두고, 0이라면 맨 앞 자릿수일 때는 , 아니면 , 음수라면 로 두면 된다.
Comment
로 정리해서 보기 전까지는 머릿속에서 떠오르는 여러 가짜 예외들이 생각을 방해했는데, 로 보는 것 보다는 로 보는게 훨씬 깔끔하고 편했다.
이 문제를 처음 봤을 때는 쉬워 보였고, 풀다가는 꼬여버려서 포기하려고도 했지만 결국 풀고 나니 충분히 시간만 들여서 깊게 생각한다면 풀 수 있는 문제 같다.
문제의 존재 자체는 예전에 알고 있었지만 그 때는 그냥
친구에게 수학 관련 문제 추천해주려다가 떠오른 문제인데, 이번 기회에 풀게 되어서 기분이 좋다.
코드
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
constexpr bool local = true;
#else
constexpr bool local = false;
#endif
#define FASTIO ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
#define ll long long
#define debug if constexpr (local) std::cout
#define endl '\n'
const ll macro[] = {0, 1, 11, 111, 1111, 11111, 111111, 1111111, 11111111, 111111111, 1111111111, 11111111111, 111111111111, 1111111111111, 11111111111111, 111111111111111, 1111111111111111, 11111111111111111, 111111111111111111, 1111111111111111111};
ll ipow(ll n, ll k){
if (k == 0) return 1;
if (k % 2) return n * ipow(n, k-1);
return ipow(n, k/2) * ipow(n, k/2);
}
ll solve(ll len, ll D){
ll x = 0;
for (int i = 0; 2*i < len-1; i++){
// last * 11...11
int last = D % 10;
ll minus = macro[len-1 - i*2] * last;
//debug << "len " << len << " D " << D << " Minus " << minus << endl;
D -= minus;
D /= 10;
if (i == 0 && last == 0){
x += ipow(10, len-1 - i);
x += ipow(10, i);
}
else if (minus > 0){
x += ipow(10, len-1 - i) * abs(last);
}
else{
x += ipow(10, i) * abs(last);
}
}
if (D != 0) return -1;
return x;
}
int main(){
int D; cin >> D;
if (D % 9){
cout << -1;
return 0;
}
D /= 9;
for (int i = 2; i < 12; i++){
ll rst = solve(i, D);
if (rst != -1){
cout << rst;
return 0;
}
}
cout << -1;
}