首页 > 代码库 > poj2282 The Counting Problem 数位dp

poj2282 The Counting Problem 数位dp

题意:给两个数l,r,求[l,r]区间内这么多数包含多少个"0" "1" "2"..."9"。 比如[1 10] 除了"1"有2个,其余数字均只有1个。

思路:数的范围为1e8,又是数的统计,一看就是数位dp。设dp[ i ] [ pos ] [ cnt ]为当前考虑数字为i,且当前考虑pos位,之前的位已经

有cnt个数字i,之后(pos+1)位与之前数位组合含数字i的个数。那么除了数字“0”需要考虑前导零之外,其他的正常求就可以了。详见代码:

/*********************************************************
  file name: poj2282.cpp
  author : kereo
  create time:  2015年01月22日 星期四 19时06分00秒
*********************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
const int sigma_size=26;
const int N=10;
const int MAXN=100000+50;
const int inf=0x3fffffff;
const double eps=1e-8;
const int mod=100000000+7;
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define PII pair<int, int>
#define mk(x,y) make_pair((x),(y))
int n,m;
int bit[N];
ll num[N],ans1[N],ans2[N],dp[N][N][N]; //dp[i][pos][cnt]表示当前考虑的是i,考虑当前位置pos,之前i的个数为cnt
ll dfs(int cur,int pos,int cnt,int pre,int flag){
    if(pos == -1) return cnt;
    if(flag && dp[cur][pos][cnt]!=-1){
        if(cur != 0)
            return dp[cur][pos][cnt];
        else if(pre)
            return dp[cur][pos][cnt];
    }
    ll ans=0;
    int x=flag ? 9 : bit[pos];
    for(int i=0;i<=x;i++){
        if(cur == 0)
            ans+=dfs(cur,pos-1,cnt+(pre && i == cur),pre || i,flag || i<x);
        else 
            ans+=dfs(cur,pos-1,cnt+(i == cur),pre || i,flag || i<x);
    }
    if(flag){
        if(cur != 0)
            return dp[cur][pos][cnt]=ans;
        else if(pre)
            return dp[cur][pos][cnt]=ans;
    }
    return ans;
}
void solve(int x){
    int len=0;
    if(!x)
        bit[len++]=x;
    while(x){
        bit[len++]=x%10; 
        x/=10;
    }
    for(int i=0;i<10;i++)
        num[i]=dfs(i,len-1,0,0,0);
}
int main(){
    while(~scanf("%d%d",&n,&m) && n+m){
        memset(dp,-1,sizeof(dp));
        if(n>m)
            swap(n,m);
        solve(n-1);
        for(int i=0;i<10;i++)
            ans1[i]=num[i];
        solve(m);
        for(int i=0;i<10;i++)
            ans2[i]=num[i];
        for(int i=0;i<10;i++){
            if(i == 0)
                printf("%lld",ans2[i]-ans1[i]);
            else 
                printf(" %lld",ans2[i]-ans1[i]);
        }
        printf("\n");
    }
	return 0;
}


poj2282 The Counting Problem 数位dp