数位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;
}
标签:string,int,DP,数位,dp,数字
From: https://www.cnblogs.com/liuyichen0401/p/18114431