SRM509 Div1 Easy - LuckyRemainder

問題

 整数から数字を1つ以上取り除き残った数字を順番はそのままに右へ詰めてできる整数らの和を9で割った余りを求めよ。

解法

 上の桁から順番に9で割った余りがそれぞれ何回出てくるかを記録していく。これをnum_iとする(0 \le i \lt 8)。j桁目の数字がnだったとき、これを使うことによりnum_{(10i + n)\%9}が現在のnum_iだけ増える。またj桁目の数字を一つだけ使うことによりnum_{n \% 9}も1増える。この二つの操作を桁を順番に下りながらやっていき、最後に各要素の和を取っていけばよいのでO(10\times \log_{10}{X})で求まる。

反省

 ちょうどこの前やったARC020のCなどの印象が強く、桁をずらしながら足して余りを求めていくという発想しか出てこなかった。もっと簡単にできるらしい

 多少でも複雑になってしまうとj桁目の数字を一つだけ使うことを忘れたりそこで9の余りを取るのを忘れたりでWAを出してしまう(しまった)ので、できるだけ簡単な解法まで落としてからコードを書き始めるということが重要なんだろうが、まぁ実際はいけそうな解法を思いついたらすぐ書き出してしまうのが人の性である。

コード

#include"bits/stdc++.h"
using namespace std;
using ll = int64_t;

class LuckyRemainder {
public:
    int getLuckyRemainder(string X) {
        vector<ll> num(9, 0);
        for (char c : X) {
            ll n = c - '0';
            auto before = num;
            for (ll i = 0; i < 9; i++) {
                num[(i * 10 + n) % 9] += before[i];
            }
            num[n % 9]++;
        }

        ll sum = 0;
        for (ll i = 0; i < 9; i++) {
            sum += num[i] * i;
        }
        return sum % 9;
    }
};