数位DP

数位DP一般解决的问题一般是位数极大, 之和组成这个数的数字有关

一般要维护 \(:\) 填到第几个数字, 是否有限制。

Magic Numbers

\(F(x)\) 表示 \(\le x\) 的满足条件元素数量

可以发现, 答案 \(F(r) - F(l - 1)\)

状态 \((i, md, flag1, falg2, sum)\) 表示填了前 \(i\) 个数字, 取模后的结果为 \(md\), 前面有没有填入一个不为 \(0\) 的数字, 有没有贴上界。

枚举当前填什么数字, 转移即可。

时间, 空间复杂度 \(O(|r| \cdot m \cdot 18)\)

#include<bits/stdc++.h>

using namespace std;

const int N = 2005, mod = 1e9 + 7;

/*

dp[i][m][0/1][0/1]  表示填了前 $i$ 个数字, 取模后的结果, 是否有前导0, 是否贴上届

*/

int dp[N][N][3][3], n, m, d, sum;

string l, r;

int DP(string s){
  n = s.size();
  s = '0' + s;
  for(int i = 1; i <= n; ++i){
    for(int j = 0; j < m; ++j){
      for(int op = 0; op <= 1; ++op){
        dp[i][j][op][0] = dp[i][j][op][1] = 0;
      }
    }
  }
  dp[0][0][1][1] = 1;
  for(int i = 1, sum = 0; i <= n; ++i){
    for(int j = 0; j < m; ++j){
      for(int op = 0; op <= 1; ++op){
        for(int k = 0; k <= 9; ++k){
          if(k != d && i % 2 == 1 || i % 2 == 0 && k == d || (op && !k)){
            dp[i][(j * 10 + k) % m][op & (k == 0)][0] = (dp[i][(j * 10 + k) % m][op & (k == 0)][0] + dp[i - 1][j][op][0]) % mod;
          }
        }
      }
    }
    for(int op = 0; op <= 1; ++op){
      for(int k = 0; k <= s[i] - '0'; ++k){
        if(k != d && i % 2 == 1 || i % 2 == 0 && k == d || (op && !k)){
          dp[i][(sum * 10 + k) % m][op & (k == 0)][(s[i] - '0') == k] = (dp[i][(sum * 10 + k) % m][op & (k == 0)][(s[i] - '0') == k] + dp[i - 1][sum][op][1]) % mod;
        }
      }
    }
    sum = (sum * 10ll + s[i] - '0') % m;
  }
  return (dp[n][0][0][0] + dp[n][0][1][1] + dp[n][0][0][1] + dp[n][0][1][0]) % mod;
}

bool S(string s){
  sum = 0;
  for(int i = 0; i < s.size(); i++){
    sum = (sum * 10ll + s[i] - '0') % m;
    if(s[i] - '0' == d && i % 2 == 0 || s[i] - '0' != d && i % 2 == 1){
      return 0;
    }
  }
  return !sum;
}

int main(){
  cin >> m >> d >> l >> r;
  cout << ((DP(r) - DP(l) + mod) % mod + S(l)) % mod;
  return 0;
}

posted @ 2024-04-04 17:52  liuyichen  阅读(2)  评论(0编辑  收藏  举报