💡

ABC 103 C - Modulo Summationのメモ

2023/08/19に公開

解いてみました。
https://atcoder.jp/contests/abc103/tasks/abc103_c

考察

X\bmod Yの結果としてあり得るのは0から Y - 1までです。例えば6なら0~5までがあり得ます。その中で最大なのはY - 1で、Yが6なら5です。これはXがどんなに大きくなっても同じで、XYの倍数の場合は余りは0、その倍数から1を引いた数だとY - 1で、これが余りとしては最大の値です。

なので、可能な限り多くのa_Nについて、その数の倍数から1を引いた数となっているようなmが見つかれば解けます。
ここまで考えたら、あることに気づきました。可能な限り多くのというか、全てのa_Nについて、倍数 - 1となる数は必ず存在するのではということです。別に最小公倍数とかでなくてもよくただの倍数でいいので、全てのa_Nをかけあわせた数は全てのa_Nの倍数となっており、ということはその数から1を引いた数は、まさに条件を満たす数なのではないかと。

そういうことであれば、a_1 - 1, a_2 - 1, ..., a_N - 1の合計値、つまり全てのa_Nそれぞれに対して1を引いて、それを全部足せば答えになるのではと。
最初に書いた通りX\bmod Yの最大値はY - 1なので、m\bmod a_Nの最大値はa_N - 1です。そして求める答えは、それらを全て足した数ということなので。

実装

そんなんでいいのかと少し心配しましたが、これで通りました。実際にmを求めなくても、理想的なmが必ず存在するとわかれば、その場合どうなるかはわかっているのでそれを計算するだけということですね。

fun main() {
    val n = readLine()!!.toInt()
    val a = readLine()!!.split(" ").map { it.toLong() }

    println(a.map { it - 1 }.sum())
}

https://atcoder.jp/contests/abc103/submissions/44685885

と言いつつ、実はその前に実際にmを求める解法で提出していました。普通にやると巨大な数になってしまいオーバーフローするので、多倍長整数を使う必要がありましたが。

単純に全部かけ合わせるのではなく、最小公倍数を求めていけばオーバーフローしないかなと雑に考えたのですが、そんなことはなく…

import java.math.BigInteger

fun main() {
    val n = readLine()!!.toInt()
    val a = readLine()!!.split(" ").map { it.toBigInteger() }

    val m = a.reduce { left, right ->
        lcm(left, right)
    } - BigInteger.ONE

    val list = a.map { m % it }

    var ans = BigInteger.ZERO
    for(i in list.indices) {
        ans += list[i]
    }

    println(ans)
}

fun gcd(a: BigInteger, b: BigInteger): BigInteger {
    return if (b == BigInteger.ZERO) {
        a
    } else {
        gcd(b, a % b)
    }
}

fun lcm(a: BigInteger, b: BigInteger): BigInteger {
    val d = gcd(a, b)
    return a / d * b;
}

https://atcoder.jp/contests/abc103/submissions/44694148

どうせ多倍長整数を使ってしまうなら、上に書いた通り単純に全部かけ合わせるのでもいいのではと思ってやってみたのがこちら。

import java.math.BigInteger

fun main() {
    val n = readLine()!!.toInt()
    val a = readLine()!!.split(" ").map { it.toBigInteger() }

    val m = a.reduce { left, right ->
        left * right
    } - BigInteger.ONE

    val list = a.map { m % it }

    var ans = BigInteger.ZERO
    for(i in list.indices) {
        ans += list[i]
    }

    println(ans)
}

https://atcoder.jp/contests/abc103/submissions/44697614

これでも普通に通りました。

(執筆時間: 26分25秒)

Discussion