[2019.10.25]训练赛T3 手机号码

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/ICEEBBING/article/details/102749304

手机号码

题目描述

人们选择手机号码时都希望号码好记、吉利。比如号码中含有几位相邻的相同数字、不含谐音不吉利的数字等。手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号码单独出售。为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数量。
工具需要检测的号码特征有两个:号码中要出现至少3个相邻的相同数字;号码中不能同时出现4和8 。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。手机号码一定是11位数,且不含前导0 。工具接收两个数 l 和 r , 自动统计出区间内所有满足条件的号码数量。l 和 r 也是11位的手机号码。
·······························

输入格式

输入文件内容只有一行,为空格分隔的两个正整数 L, R

输出格式

输出文件内容只有一行,为一个整数,表示满足条件的手机号数量。

分析:

很显然, 使用数位dp, 详见注释

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXM 15
#define LL long long
#define Int register int
using namespace std;
LL num[MAXM];
LL dp[MAXM][MAXM][MAXM][2][2][2][2];
inline LL Max(LL x,LL y)
{
    return x > y ? x : y;
}
inline LL Min(LL x,LL y)
{
    return x < y ? x : y;
}
inline void read(LL &x)
{
 x = 0;
 LL f = 1;
 char s = getchar();
 while (s < '0' || s > '9')
 {
     if (s == '-')
         f = -1;
     s = getchar();
 }
 while (s >= '0' && s <= '9')
 {
     x = (x << 3) + (x << 1) + (s ^ 48);
     s = getchar();
 }
 x *= f;
}
LL Num_dp(int p,int a,int b,bool l,bool s,bool c4,bool c8)
{
 /*
 p : 当前数位
 a : p + 1位的数
 b : p + 2位的数, 如果为前导0则为 -1
 l : 判断连续
 s : 判断是否前面已经严格小于, 方便填数
 c4、c8 : 判断 4 和 8 
 */
    if (c4 && c8)
        return 0;
    if (p <= 0)
        return l;
    if (~ dp[p][a][b][l][s][c4][c8])
        return  dp[p][a][b][l][s][c4][c8];
    LL Sum = 0, Limit = ! s ? num[p] : 9;
    for (Int i = 0; i <= Limit; ++ i)
        Sum += Num_dp(p - 1, i, a, l || (i == a && a == b), s || (i < Limit), c4 || (i == 4), c8 || (i == 8));
    return dp[p][a][b][l][s][c4][c8] = Sum;
}
LL solve(LL x)
{
    if (x < 10000000000ll)
        return 0;
    memset(dp, -1, sizeof dp);
    int len = 0;
    while ( x )
    {
        num[++ len] = x % 10;
        x /= 10;
    } 
    LL Ans = 0;
    for (Int i = 1; i <= num[len]; ++ i)
        Ans += Num_dp(10, i, 0, 0, i < num[len], i == 4, i == 8);
    return Ans;
}
int main()
{
    LL L, R;
    read( L ); read( R );
    printf("%lld", solve( R ) - solve(L - 1));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ICEEBBING/article/details/102749304
今日推荐