P4124 [CQOI2016]手机号码 数位DP
工具需要检测的号码特征有两个:号码中要出现至少 33 个相邻的相同数字;号码中不能同时出现 88 和 44。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。
手机号码一定是 1111 位数,前不含前导的 00。工具接收两个数 LL 和 RR,自动统计出 [L,R][L,R] 区间内所有满足条件的号码数量。LL 和 RR 也是 1111 位的手机号码。
套路的数位DP。
维护前一个数,前前一个数即可。
ll dp[11][10][10][2][2][2][2][2]; vector<int> v; int len; void init(ll n) { v.clear(); while (n) v.push_back(n % 10), n /= 10; reverse(v.begin(), v.end()); len = v.size(); } ll dfs(int cur, int x, int y, bool f, bool g, bool num, bool _4, bool _8) { if (_4 && _8) return 0; if (cur == len ) return num; if (dp[cur][x][y][f][g][num][_4][_8] != -1) return dp[cur][x][y][f][g][num][_4][_8]; int t = 9; if (f) t = v[cur]; ll ans = 0; for (int i = 0; i <= t; i++) { if (g) { if (!i) ans += dfs(cur + 1, 0, 0, f & (i == t), 1, 0, 0, 0); else ans += dfs(cur + 1, i, 0, f & (i == t), 0, 0,i == 4, i == 8); } else { ans += dfs(cur + 1, i, x, f & (i == t), 0, num || (i == x && i == y), _4 || (i == 4), _8 || (i == 8)); } } return dp[cur][x][y][f][g][num][_4][_8] = ans; } ll solve(ll x) { init(x); memset(dp, -1 , sizeof dp); return dfs(0, 0, 0, 1, 1, 0, 0, 0); } int main() { ll L, R; L = readll(), R = readll(); Put(solve(R) - solve(L - 1)); }