0w1

AOJ Zig-Zag Numbers ( 桁DP )

Zig-Zag Numbers | Aizu Online Judge
一桁の場合はなんだとあれ必ずZig-Zag数という性質上、「今有効一桁だけ」、「今全部0」、「それ以外の状態」と三つに分けてそれぞれ別に判断しなけらばならない。桁dpをする時はleading zeroが方法数にどんな影響を与えるのかを予めよく考えよう。

#include <bits/stdc++.h>
using namespace std;
const int MAXM = 500;
const int MAXLEN = 500 + 5;
const int MOD = 1e4;
#define rep( i, a ) for(int i = 0; i < (int)( a ); ++i)

string a, b;
int m;

// pos, less, 0s leading / 1dig leading / decreasing / increasing, last dig, % m
int way[MAXLEN][2][4][10][MAXM];
int dp(const string &s, bool inc){ // inc: <= s or < s
    memset( way, 0, sizeof(way) );
    way[0][0][0][0][0] = 1;
    rep( i, s.size() ) rep( j, 2 ) rep( k, 4 ) rep( l, 10 ) rep( p, m ){
        int lim = j ? 9 : s[ i ] - '0';
        rep( d, lim + 1 ){
            if( k == 0 )
                ( way[i + 1][j || d < lim][d != 0][d][d % m]
                  += way[i][j][k][l][p] ) %= MOD;
            else if( k == 1 && d != l )
                ( way[i + 1][j || d < lim][d < l ? 2 : 3][d][( p * 10 + d ) % m]
                  += way[i][j][k][l][p] ) %= MOD;
            else if( k == 2 && d > l )
                ( way[i + 1][j || d < lim][3][d][( p * 10 + d ) % m]
                  += way[i][j][k][l][p] ) %= MOD;
            else if( k == 3 && d < l )
                ( way[i + 1][j || d < lim][2][d][( p * 10 + d ) % m]
                  += way[i][j][k][l][p] ) %= MOD;
        }
    }
    int res = 0;
    rep( j, 2 ) rep( k, 4 ) rep( l, 10 ){
        if( !inc && !j ) continue; // -> s, if not included, discard it
        ( res += way[ s.size() ][j][k][l][0] ) %= MOD;
    }
    return res;
}

void solve(){
    int ans = dp( b, true ) - dp( a, false ); // way( [ 0, b ] ) - way( [ 0, a ) ) = way( [ a, b ] )
    ans %= MOD; ans += MOD; ans %= MOD;
    cout << ans << endl;
}

int main(){
    ios::sync_with_stdio(false);
    cin >> a >> b >> m;
    solve();
    return 0;
}