お得?
- 桁DPは「知らなきゃ解けないけど、知っていればやるだけ」らしい
- 習得しておきたい
問題「D - 禁止された数字」
解法
ll dp[25][2][2];
code 抜粋
bool fn(ll v){
if(v==4 || v==9){
return true;
}else{
return false;
}
}
int main(){
ll v = ctoi(s[0]);
rep(i, v+1){
if(i==v){
if(fn(i)){
dp[0][0][1] += 1;
}else{
dp[0][0][0] += 1;
}
}
else{
if(fn(i)){
dp[0][1][1] += 1;
}else{
dp[0][1][0] += 1;
}
}
}
FOR(i, 1, L){
ll v = ctoi(s[i]);
if(fn(v)){
dp[i][0][1] += dp[i-1][0][0];
dp[i][0][1] += dp[i-1][0][1];
}else{
dp[i][0][0] += dp[i-1][0][0];
dp[i][0][1] += dp[i-1][0][1];
}
rep(j, v){
if(fn(j)){
dp[i][1][1] += dp[i-1][0][0];
dp[i][1][1] += dp[i-1][0][1];
}else{
dp[i][1][0] += dp[i-1][0][0];
dp[i][1][1] += dp[i-1][0][1];
}
}
rep(j, 10){
if(fn(j)){
dp[i][1][1] += dp[i-1][1][0];
dp[i][1][1] += dp[i-1][1][1];
}else{
dp[i][1][0] += dp[i-1][1][0];
dp[i][1][1] += dp[i-1][1][1];
}
}
}
}
- ポイントは、添字を間違えないこと
- fixed to fixed (0->0)
- fixed to smaller (0->1)
- smaller to smaller (1->1)
- の3分岐あるが、添字もそれに対応するので確認はしやすい
別解
// i桁まで見て
// j : smaller flag
// 禁止されていない数を作れる個数
ll dp[20][2];
桁DPの他の問題
- D - XXOR
- S - Digit Sum
- E - Almost Everywhere Zero
- TDPC E - 数
桁DPの知見
- 10000桁などの数値Kが与えれることが多いが、Kが小さいものならlong longに収まってナイーブ解法が書きやすい問題が多い
- サンプルが合ったけど提出してWAだった時は、ナイーブ解法.cppを作って正しいテストケースを作ればデバッグしやすい
問題集 (cf)
LOOSE, TIGHT
えびちゃん@rsk0315_h4x.
桁 DP は 0 とか 1 とかでアクセスしてると
意味不明になるので、
名前(loose/tight とか)をつけてやるのがおすすめ
const int TIGHT=0;
const int LOOSE=1;