洛谷 P4124 [CQOI2016]手机号码

题意简述

求l~r之间不含前导零,至少有三个相邻的相同数字,不同时含有4和8的11位正整数的个数

题解

数位DP,注意在l,r位数不够时补至11位

代码

#include <cstdio>
#include <cstring>
typedef long long ll;
int cnt;
int num[20];
ll l, r;
ll dp[20][2][10][10][2][2];
bool _4, _8, _f;
ll dfs(int len, int p1, int p2, bool limit, bool lead, bool flag, bool f4, bool f8)
{
    ll s = 0;
    if (len < cnt && lead) return 0;
    if (len == 0) return flag;
    ll& dp = ::dp[len][flag][p1][p2][f4][f8];
    if (!limit && ~dp) return dp;
    int mx = limit ? num[len] : 9;
    for (register int i = 0; i <= mx; ++i)
    {
        if ((i == 4 && f8) || (i == 8 && f4)) continue;
        _4 = f4 || (i == 4); _8 = f8 || (i == 8);
        _f = flag || (i == p1 && p1 == p2);
        s += dfs(len - 1, i, p1, limit && (i == mx), lead && !i, _f, _4, _8);
    }
    if (!limit) dp = s;
    return s;
}
ll solve(ll x)
{
    cnt = 0;
    memset(dp, -1, sizeof(dp));
    while (x) {num[++cnt] = x % 10; x /= 10; }
    while (cnt < 11) num[++cnt] = 0;
    return dfs(cnt, -1, -1, 1, 1, 0, 0, 0);
}
int main()
{
    scanf("%lld%lld", &l, &r);
    printf("%lld", solve(r) - solve(l - 1));
}

猜你喜欢

转载自www.cnblogs.com/xuyixuan/p/9905395.html