BOJ 13172 - Σ

BOJ 13172 - Σ

“분할 정복을 이용한 거듭 제곱”

BOJ 13172 - Σ

문제 링크



#include <bits/stdc++.h>
#define all(x) (x).begin(), (x).end()
#define rep(i, a, b) for (int i = (a); i < (b); ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f;
using namespace std;

ll MOD = 1000000007;
ll M, a, b;

ll np(ll a, ll b) {
    ll ans = 1;
    while (b)
    {
        if (b & 1) ans = ans * a % MOD;
        b /= 2;
        a = a * a % MOD;
    }
    return ans;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin>>M;
    ll ans = 0;
    for (int i = 0; i < M; i++) 
    {
        cin>>a>>b;
        // b / a = b * a^(1000000007 - 2) % MOD
        ans += (b * (np(a, MOD - 2))) % MOD;
    }
    cout << ans % MOD;
    return 0;
}
  • 두손두발 다들었다… 가장 간소하게 이해한 바로는 두 번째로 들어온 수의 1,000,000,005승을 구하는 것이 핵심이고, 분할 정복을 이용해서 구한다.
ll np(ll a, ll b) {
    ll ans = 1;
    while (b)
    {
        if (b & 1) ans = ans * a % MOD;
        b /= 2;
        a = a * a % MOD;
    }
    return ans;
}
  • 문제의 본질까지 이해하는 건 무리일 것 같고, 그것을 차치하더라도 분할정복을 이용한 계승 구하기 코드는 매우 유용할 것 같다.