HDOJ 5787 K-wolf Number 数位DP

50 篇文章 0 订阅

数位DP的一道所谓的水题!

但是呢,必须得胆子大!

题意:求区间【L,R】中有多少个满足条件的十进制数

条件是:任意连续K个数值都不相同,K=2,3,4,5


dp最难的是设计状态和状态转移啊!

K很小,所以可以每一个有意义的数位都来一维来表示呗

dp[pos][p1][p2][p3][p4]

pos表示当前位,p4表示前一位。这里要考虑前导0的情况,p4=10的时候表示前一位为0

然后呢,最特殊的情况是:全是0的情况


转移呢,枚举即可

判断条件要根据K来说咯,如果K=2,那么当前枚举的这一位不等于p4

K=3,4,5是同理的


代码如下:

#include<bits/stdc++.h>
using namespace std;

#define LL __int64

const int maxn=25;
int K,digit[maxn];
LL dp[maxn][11][11][11][11];

bool check(int p1,int p2,int p3,int p4,int u){
    if (K==2) return u!=p4;
    else if (K==3) return u!=p4&&u!=p3;
    else if (K==4) return u!=p4&&u!=p3&&u!=p2;
    else return u!=p4&&u!=p3&&u!=p2&&u!=p1;
}

LL dfs(int pos,int p1,int p2,int p3,int p4,bool flag){
    if (pos==0) return p4!=10;
    if (flag&&dp[pos][p1][p2][p3][p4]!=-1) return dp[pos][p1][p2][p3][p4];
    LL res=0;
    int maxnum=flag?9:digit[pos];
    for(int i=0;i<=maxnum;i++){
        if (p4==10&&i==0)
            res+=dfs(pos-1,10,10,10,10,flag||i<maxnum);
        else if (check(p1,p2,p3,p4,i))
            res+=dfs(pos-1,p2,p3,p4,i,flag||i<maxnum);
    }
    if (flag) dp[pos][p1][p2][p3][p4]=res;
    return res;
}

LL calc(LL x){
    int len=0;
    while(x){
        digit[++len]=x%10;
        x/=10;
    }
    return dfs(len,10,10,10,10,0);
}

int main(){
    //freopen("input.txt","r",stdin);
    LL L,R;
    while(scanf("%I64d%I64d%d",&L,&R,&K)!=EOF){
        memset(dp,-1,sizeof(dp));
        printf("%I64d\n",calc(R)-calc(L-1));
    }
    return 0;
}

注意:

在数位dp分隔数位的时候

一定是digit【++len】而不是digit【len++】

一方面是因为最后的初始边界是len==0,就算 改成len==-1也是不行的

因为:dp的初始化会导致有问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值