解法
桁DPと呼ばれるらしい。a以上b以下のジグザグ数の個数は、b以下のジグザグ数 - a-1以下のジグザグ数で求められる。
dp[自由に選べるか][直前が... 0:沿ってる 1:増 2:減][前の桁の数][余り][今の場所] という配列を用意。
自由に選べるかは、桁の数字に沿わなくなるまでfalseでやる。
余りは、(前の桁までの余り * 10 + 今の桁) % 倍数でやる。
ソース
#include<iostream> #include<string> #include<algorithm> using namespace std; #define MOD 10000 string s; short dp[2][3][10][500][501]; //[free][増減][prev][余り][index] int m; int solve( bool fr, int updw, int pre, int mod, int index){ if( index == s.size() ) return !mod; if( dp[fr][updw][pre][mod][index] != -1 ) return dp[fr][updw][pre][mod][index]; int ret = 0, end = fr ? 9 : s[index]; for(int i = 0, u ; i <= end ; i++ ){ switch(updw){ case 0: //さいしょ if( pre && pre == i ) continue; else if( pre == 0 ) u = 0; else if( pre > i ) u = 1; else u = 2; break; case 1: //次あっぷ if( pre >= i ) continue; else u = 2; break; case 2: //次だうん if( pre <= i ) continue; else u = 1; break; } ret += solve( fr|(i!=s[index]), u, i, (mod*10+i)%m, index+1); } return dp[fr][updw][pre][mod][index] = ret % MOD; } void java(){ for(int i = s.size() - 1 ; i >= 0 ; i-- ){ if(s[i] == 0) s[i] = 9; else{ s[i]--; break; } } } int main(){ string s1; cin >> s >> s1 >> m; for(int i = 0 ; i < s.size() ; i++ ) s[i] -= '0'; java(); fill_n( ****dp, 2 * 3 * 10 * 500 * 501, -1); int an = solve( 0, 0, 0, 0, 0); s = s1; for(int i = 0 ; i < s.size() ; i++ ) s[i] -= '0'; fill_n( ****dp, 2 * 3 * 10 * 500 * 501, -1); int bn = solve( 0, 0, 0, 0, 0); cout << ( bn - an + MOD ) % MOD << endl; }
0 件のコメント:
コメントを投稿