[CQOI2016] 手机号码

[CQOI2016] 手机号码

题目大意:求\([L,R]\)之间11位的数字个数,要符合要有三连数字,且\(8\)\(4\)不能同时出现

Solution

看代码吧

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#define sc(x) scanf("%lld", &x)

typedef long long ll;

ll dp[11][11][11][2][2][2];//dp[位置][上一个的上一个][上一个][是否有4][是否有8][是否三连]
int a[105];

ll dfs(int pos, int llast, int last, bool if4, bool if8, bool if3, bool dflag, bool uflag){
    if(pos == -1) return if3 ? 1 : 0;//如果出现过连续三个相同的数,才符合条件。 
    if(!uflag && !dflag && last != -1 && llast != -1 && dp[pos][llast][last][if4][if8][if3] != -1)
        return dp[pos][llast][last][if4][if8][if3];//不卡上下界才是一个完整的qwq
    int up = uflag ? a[pos] : 9;
    int down = dflag ? 1 : 0;
    ll tmp = 0;
    for(int i = down; i <= up; ++i){
        if(if4 && i == 8) continue;
        if(if8 && i == 4) continue;
        tmp += dfs(pos - 1, last, i, if4 || (i == 4), if8 || (i == 8), if3 || (llast == last && last == i), 0, uflag && (i == a[pos]));
    } 
    if(!uflag && !dflag && last != -1 && llast != -1) dp[pos][llast][last][if4][if8][if3] = tmp;
    return tmp;
}

inline ll cal(ll x){
    int cnt = -1;
    memset(a, 0, sizeof(a));
    while(x){
        a[++cnt] = x % 10;
        x /= 10;
    }
    return cnt != 10 ? 0: dfs(cnt, -1, -1, 0, 0, 0, 1, 1);//10位 例如1000000000, 就不存在
}

int main(){
    ll l, r;
    sc(l), sc(r);
    memset(dp, -1, sizeof(dp));
    printf("%lld\n", cal(r) - cal(l - 1));
    return 0;
}
posted @ 2018-09-10 17:51  LMSH7  阅读(513)  评论(1编辑  收藏  举报