Loading

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));
}

 

posted @ 2020-08-08 21:56  MQFLLY  阅读(106)  评论(0编辑  收藏  举报