POJ 2282 The Counting Problem (数位dp)

来源:互联网 发布:vscode web插件 编辑:程序博客网 时间:2024/06/04 19:32

题目:http://poj.org/problem?id=2282

题意:求出数a-b之间(0 < a, b < 100000000),出现的0,1...9的个数。

思路:用数位dp记忆化搜索模版。

代码:

#include <stdio.h>#include <string.h>#include <math.h>#include <algorithm>#define MOD 1000000007#define INF 0x7fffffffusing namespace std;typedef long long ll;int bit[20];ll f[15][20][20][5];ll dp(int c, int pos, int sta, int flag, int str){    //当前统计数字c出现的个数    //第len到pos+1位已确定,现在要确定第pos位    //前面已经出现了sta个c    //flag=1,不论第pos位为什么都比给定的数小    //str=1,第len到第pos+1位出现了不是0的数    if(pos == 0) return sta;    if(flag && f[c][pos][sta][str] != -1) return f[c][pos][sta][str];    ll ans = 0;    int x = flag ? 9 : bit[pos];    for(int i = 0; i <= x; i++)    {        if(i == c)        {            if(str)                ans += dp(c, pos - 1, sta + 1, flag || i < x, str);            else                ans += dp(c, pos - 1, sta, flag || i < x, str);        }        else ans += dp(c, pos - 1, sta, flag || i < x, 1);    }    if(flag) f[c][pos][sta][str] = ans;    return ans;}ll cal(ll n, int c){    int len = 0;    while(n)    {        bit[++len] = n % 10;        n /= 10;    }    int str = 1;    if(c == 0) str = 0;    ll ans = dp(c, len, 0, 0, str);    return ans;}int main(){    #ifdef LOCAL    freopen("dpdata.txt", "r", stdin);    #endif    ll a, b;    memset(f, -1, sizeof(f));    while(scanf("%I64d%I64d", &a, &b) != EOF)    {        if(!a && !b) break;        if(a > b)        {            int temp = a; a = b; b = temp;        }        for(int i = 0; i <= 9; i++) //int i = 0;        {            if(i != 0) printf(" ");            if(a == 0 && i == 0)                printf("%I64d", cal(b, i) - cal(a - 1, i) + 1);            else                printf("%I64d", cal(b, i) - cal(a - 1, i));        }        printf("\n");    }    return 0;}


0 0
原创粉丝点击