[BOJ] 1494 절댓값 수열

문제#

image.png

출처: https://boj.kr/1494


어떻게 풀었나?#

$S_0 = A,\; S_1=a$라 두고 숫자를 쭉 나열해보면 아래와 같이 a가 계속 반복됨을 알 수 있다.

A
a
A-a
A-2a
a
A-3a
A-4a
a
A-5a
A-6a
...

그리고 중간에 A-6a 형태로 썼지만, 사실 A가 6a보다 커야 A-6a인거고 중간에 A-4a부터 음수가 되었다 하면, 4a-A로 그 결과가 달라질 것이다. 그러므로 $A \ge 2a\cdot s$를 만족하는 $s$를 찾으면 현재 $S_k$를 보고 있다고 할 때, $S_{k+3s}$까지 건너뛸 수 있다. 이 부분이 메인 아이디어고, 그 외에는 건너뛰지 않고 1 step씩 다음 $S_i$를 구하면 된다.

추가로 a가 0일 땐 A다음 a가 나오는 형태가 그대로 유지된 채로 현재 step + 3의 배수만큼 건너뛸 수 있다.

이를 코드로 구현하면 아래와 같다.


정답 코드#

#include <bits/stdc++.h>
using ll = long long;
using namespace std;
inline ll ABS(ll x) {
    return (x<0LL)?-x:x;
}
ll N;
ll f(ll A, ll a, ll n) {
    ll rmn = N-n;
    if(rmn == 0) return A;
    else if(rmn == 1) return a;
    else if(rmn == 2) return ABS(A-a);
    else {
        if(a==0) {
            return f(A, a, n+(rmn/3LL)*3LL);
        }
        ll mxs = A/(2*a);
        if(mxs==0LL) {
            return f(a,ABS(A-a),n+1);
        }
        else {
            ll lo=1, hi=mxs;
            while(lo<=hi) {
                ll mid = (lo+hi)/2;
                if(n+3*mid<=N) lo=mid+1;
                else hi=mid-1;
            }
            ll s = lo-1;
            return f(A-2*a*s, a, n+3*s);
        }
    }
    
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    ll s0, s1;
    int n;
    cin >> s0 >> s1 >> n;
    for(int i=0; i<n; i++) {
        cin >> N;
        printf("%lld\n", f(s0,s1,0));
    }
    return 0;
}

Comment#

유클리드 알고리즘, Modular Inverse관련해서 공부하다가 관련 문제가 없을까 해서 boj에서 하나 골라서 푼건데, 전혀 유클리드 알고리즘과 상관없는 방식으로 풀었다. ‘난이도 기여’에 나온 사람들의 의견을 보니 확장 유클리드 알고리즘을 사용해서 풀 수도 있는 것 같다.

내가 풀 때는 플래티넘1 문제였는데, 그 정도 난이도는 아닌 것 같고 플래티넘3-5 수준의 문제가 아닐까 싶다. 내가 플3으로 난이도 평가를 했더니 해당 문제 난이도가 플2로 낮아졌다. 코포로 따지면 Div2. 1500-1750 수준의 문제가 아닐까 싶다.