码迷,mamicode.com
首页 > 其他好文 > 详细

数位dp

时间:2020-01-15 21:12:13      阅读:67      评论:0      收藏:0      [点我收藏+]

标签:直接   size   span   syn   ==   stream   def   for   tmp   

给出一个区间,求区间里满足某些条件的数有几个

  • 直接暴力求解
  • 打表+前缀和
  • 数位dp

当区间范围很大时,时间复杂度需要,无法暴力,只能用数位dp来做

模板求[1,n]的数字里不含49的个数

数组a[i]存放n的值,如果n是1234,那么数组就是{4,3,2,1}但是dfs是从最高位1开始的

数组\(dp[i][j]\)是指当到达第i位,该数字的前缀是j,且满足条件的情况的个数

int up = limit ? a[pos] : 9;//枚举上限

指的是枚举的一个上限,如果a[pos] 是 5,那么数字只能枚举\(0-5\)

如235百位是0-2枚举,且在这种情况下,枚举十位0-3,个位枚举0-5

将时间复杂度度从235变为3 * 4 * 6 = 72

即时间复杂度从O(n)变为各位上的数字加1后的乘积

最后关于最高位的0的时候,也是可以的,比如033 也就是 33

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define ios_fuck ios::sync_with_stdio(0)
using namespace std;
typedef long long ll;
int a[50];
ll dp[50][10];
ll dfs(int pos,int pre,bool limit){
    if(pos == -1) return 1;//结束
    if(!limit && dp[pos][pre] != -1) return dp[pos][pre];
    int up = limit ? a[pos] : 9;//枚举上限
    ll tmp = 0;
    for(int i = 0; i <= up; i++){
        if(pre == 4 && i == 9)continue;
        // if(i == 4) continue;
        tmp += dfs(pos - 1,i,limit && i == a[pos]);
    }
    if(!limit) dp[pos][pre] = tmp;
    return tmp;
}
ll solve(ll x){
    int pos = 0;
    while(x){
        a[pos++] = x % 10;
        x /= 10;
    }
    return dfs(pos-1,0,true);
}
int main(){
    ll ri;
    int t;
    scanf("%d",&t);
    memset(dp,-1,sizeof(dp));
    while(t--){
        scanf("%lld",&ri);
        printf("%lld\n",solve(ri));
    }

    return 0;
}

数位dp

标签:直接   size   span   syn   ==   stream   def   for   tmp   

原文地址:https://www.cnblogs.com/Emcikem/p/12198792.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!