BZOJ 4521 手机号码 数位dp

传送门

题解:开个6维的dp函数,第一维记录位置,第二维记录当前位置的前两个,第三维记录当前位置的前一个,第四维记录是否出现4,第五位记录是否出现8,第六维记录是否满足出现三个连续的数字。特判1e10

 
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <vector>
#include <cstring>
#include <iomanip>
#include <set>
#include<ctime>
//#include<unordered_map>
//CLOCKS_PER_SEC
#define se second
#define fi first
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define Pii pair<int,int>
#define Pli pair<ll,int>
#define ull unsigned long long
#define pb push_back
#define fio ios::sync_with_stdio(false);cin.tie(0)
const int N=100;
const ull base=163;
const int INF=0x3f3f3f3f;
using namespace std;
int a[N];
ll dp[20][20][20][2][2][2];
ll dfs(int pos,int pre1,int pre2,bool lead,bool limit,bool flag,bool op,bool oo){//op--4  oo-8
    if(op&&oo)return 0;
    if(pos==-1)return flag==1;
    if(!lead&&!limit&&dp[pos][pre1][pre2][op][oo][flag]!=-1)return dp[pos][pre1][pre2][op][oo][flag];
    int up=limit?a[pos]:9;
    ll tmp=0;
    for(int i=lead?1:0;i<=up;i++){
        if(!flag){
            int io=0;
            if(pre1==pre2&&i==pre2)io=1;
            tmp+=dfs(pos-1,pre2,i,0,limit&&i==a[pos],io,op||i==4,oo||i==8);
        }
        else{
            tmp+=dfs(pos-1,pre2,i,0,limit&&i==a[pos],flag,op||i==4,oo||i==8);
        }
    }
    if(!limit)dp[pos][pre1][pre2][op][oo][flag]=tmp;
    return tmp;
}
ll solve(ll x){
    int pos=0;
    while(x){
        a[pos++]=x%10;
        x/=10;
    }
    return dfs(pos-1,10,10,true,true,0,0,0);
}
int main(){
    ll a,b;
    cin>>a>>b;
    memset(dp,-1,sizeof(dp));
    printf("%lld\n",a==10000000000?solve(b):solve(b)-solve(a-1));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Mrleon/p/9097723.html