NF

地方で働くプログラマ

ABC154復習中(桁DPできない日記)その2

ABC154復習中(桁DPできない日記) - NF

続きです。取り合えず、3を数えるプログラムは出来ましたが、ABC154-Eはもう少し応用が必要そうでまだ解けてません。取り合えず、3を数える方だけ載せておきます。100までは参考サイト様と出力が一致することを確認済みです。

その2とか言ってますが次が最終回(=ABC154-EのAC)にしたい。

#include <iostream>
#include <string>
#include <string.h>
using namespace std;

int foo(std::string n)
{
    // 該当する数字の数を格納する配列
    // 桁数×未満フラグ(該当桁がn未満なら0、nなら1)×3が付くかのフラグ
    const int digit = n.size();
    int dp[digit][2][2];
    memset(dp, 0, sizeof(int)*digit*2*2);

    int x0 = n[0] - '0';
    if(x0 < 3){
        dp[0][0][0] = x0; // 0~(x0-1)までのx0個
        dp[0][0][1] = 0;  // x0が3未満なので0個
        dp[0][1][0] = 1;  // x0が3未満なので1個
        dp[0][1][1] = 0;  // x0が3未満なので0個
    }else if(x0 == 3){
        dp[0][0][0] = x0; // 0~(x0-1)までのx0個
        dp[0][0][1] = 0;  // x0が3だが、3未満でないので0個
        dp[0][1][0] = 0;  // x0が3なので0個
        dp[0][1][1] = 1;  // x0が3なので1個  
    }else if(x0 > 3){
        dp[0][0][0] = x0-1; // 0~(x0-1)までのx0個から3を引いた(x0-1)個
        dp[0][0][1] = 1;    // x0が3より大きいので3の1個
        dp[0][1][0] = 1;    // x0が3より大きいのでx0の1個
        dp[0][1][1] = 0;    // x0が3ではないので0個
    }
    //printf("%d %d %d %d\n", dp[0][0][0], dp[0][0][1], dp[0][1][0], dp[0][1][1]);

    for(int i=1; i<digit; i++){
        const int x = n[i] - '0';
        if(x < 3){
            dp[i][0][0] = dp[i-1][0][0]*(10-1) + dp[i-1][0][1]*0 + dp[i-1][1][0]*x;
            dp[i][0][1] = dp[i-1][0][0]*1 + dp[i-1][0][1]*10 + dp[i-1][1][1]*x;
            dp[i][1][0] = dp[i-1][1][0]*1 + dp[i-1][1][1]*0;
            dp[i][1][1] = dp[i-1][1][0]*0 + dp[i-1][1][1]*1;
        }else if(x == 3){
            dp[i][0][0] = dp[i-1][0][0]*(10-1) + dp[i-1][0][1]*0 + dp[i-1][1][0]*x;
            dp[i][0][1] = dp[i-1][0][0]*1 + dp[i-1][0][1]*10 + dp[i-1][1][1]*x;
            dp[i][1][0] = 0;
            dp[i][1][1] = 1;
        }else if(x > 3){
            dp[i][0][0] = dp[i-1][0][0]*(10-1) + dp[i-1][0][1]*0 + dp[i-1][1][0]*(x-1);
            dp[i][0][1] = dp[i-1][0][0]*1 + dp[i-1][0][1]*10 + dp[i-1][1][0]*1 + dp[i-1][1][1]*x;
            dp[i][1][0] = dp[i-1][1][0]*1 + dp[i-1][1][1]*0;
            dp[i][1][1] = dp[i-1][1][0]*0 + dp[i-1][1][1]*1;
        }
        //printf("%d %d %d %d\n", dp[i][0][0], dp[i][0][1], dp[i][1][0], dp[i][1][1]);
    }

    //cout << dp[digit-1][0][1] + dp[digit-1][1][1] << endl; 
    return dp[digit-1][0][1] + dp[digit-1][1][1];
}

int main()
{
    std::string n;
    cin >> n;
    cout << foo(n) << endl;
    return 0;
}