No.41 貯金箱の溜息(EASY)

No.41 貯金箱の溜息(EASY) - yukicoder

  • 10^5 くらいの再帰をやろうとして stackoverflow してしまった...。
  • 累積 DP がなんで必要かが一瞬わからなかった。
  • カテゴリ的には座標圧縮も入るのか。確かに。
class SighOfSavingsBoxEasy {
public:
    void solve(void) {
            // Mk/111111LL <= 10^10/10^5 = 10^5 なので再帰でやると stackoveflow する。
            // よって dp でやる必要がある。
            // 111111LL 未満は 1 のコインで払う 1 通りしかないので
            // Mk/111111LL を 1~9 までのコインで払う払い方と考える
            ll MaxM = (ll)1E+10;
            MaxM = MaxM/111111LL;

            // dp[i] := i 円を 1~9 までのコインで払う払い方
            vector<ModInt> dp(MaxM+1, 0);
            dp[0] = 1; // 111111LL 未満の払い方は 1 通り

            // O(10*MaxM) <= 10^6
            for (int j = 1; j <= 9; ++j)
            for (ll i = 0; i < MaxM; ++i)
            {
                if (i+j <= MaxM)
                    dp[i+j] += dp[i];
            }

            // dp2[i] := i 円までを 1~9 のコインで払う払い方
            //
            // これは j 円までを (j < i) 1~9 のコインではらって残りを
            // 本来の 1 円コインで払うという払い方ができるから累積 DP が必要
            //
            vector<ModInt> dp2(MaxM+1, 0);
            dp2[0] = 1;
            for (ll i = 1; i <= MaxM; ++i)
                dp2[i] = dp2[i-1] + dp[i];

            int T;
            cin>>T;
            REP(i,T)
            {
                ll m;
                cin>>m;
                cout<<dp2[m/111111LL]<<endl;
            }
    }
};