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;
}
时间: 2024-11-18 20:55:03

poj2282 The Counting Problem 数位dp的相关文章

UVa 1640 The Counting Problem (数位DP)

题目 题目大意 给出\(a\).\(b\), 统计\(a\)和\(b\)(包含\(a\)和\(b\))之间的整数中, 数字\(0, 1, 2, 3, 4, 5, 6, 7, 8, 9\)分别出现了多少次.\(1 ≤ a, b ≤ 10^8\).注意, \(a\)有可能大于\(b\). 题解 设\(f_d(n)\)表示\(0 \cdots n\)中数字\(d\)出现的个数, 则求的是\(f_d(a) - f_d(b - 1)\). 暴力显然是会\(TLE\)的, 我们可以分段来求.例如我们要求\(

POJ2282 The Counting Problem

题意 Language:DefaultEspa?ol The Counting Problem Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 5070 Accepted: 2590 Description Given two integers a and b, we write the numbers between a and b, inclusive, in a list. Your task is to calcula

LA 6527 Counting ones 数位dp

题意:给两个数A,B,求二进制表示下,区间[A,B]之前总共有多少个1. 思路:设dp[pos][ cnt ]为当前考虑pos位,之前的数中已经有cnt个1的时候,(pos+1)个数位与之前数位组成的含有1的个数.详见 代码: /********************************************************* file name: LA6527.cpp author : kereo create time: 2015年02月06日 星期五 15时58分10秒 *

nowcoder A hard problem /// 数位DP

题目大意: 称一个数x的各个数位之和为f(x) 求区间L R之间 有多少个数x%f(x)==0 #include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define LL long long #define inc(i,j,k) for(int i=j;i<=k;i++) #define dec(i,j,k) for(int i=j;i>=k;i--) #define gcd(i,j) __gcd(

HDU 5106 Bits Problem (数位DP)

题目地址:HDU 5106 这个题要定义个dp结构体,dp[i][j].sum表示当前第i位还剩j个1的时候的和,dp[i][j].tot表示当前第i位还剩j个1的时候的符合要求的个数.不记录个数的话,当前位上的1无法跟着低位的出现而累加. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #i

UVa1640 - The Counting Problem(数位统计)

题意: 统计两个整数a,b之间各个数字(0~9)出现的次数,如1024和1032,他们之间的数字有1024 1025 1026 1027 1028 1029 1030 1031 1032 总共有10个0,10个1,3个3等等. 分析: 因为前导0的干扰,为了计算方便暂时都先计算在内,之后再减; 如果是0~199,那么百位上的0和1各出现一次,s剩下的就是两个00~99,总共两百个二位数,而每个数出现的次数都一样,都是2*(99-00+1)/10; 那么任意的数都可以分解成类似的数字,如3426,

UVA 1640 The Counting Problem UVA1640 求[a,b]或者[b,a]区间内0~9在里面各个数的数位上出现的总次数。

/** 题目:UVA 1640 The Counting Problem UVA1640 链接:https://vjudge.net/problem/UVA-1640 题意:求[a,b]或者[b,a]区间内0~9在里面各个数的数位上出现的总次数. 思路:数位dp: dp[leadzero][i][j][k]表示前面是否选过非0数,即i长度之后可以第一个出现0,而不是前导0,长度为i,前面出现j,k次,j出现的次数. */ #include<iostream> #include<cstri

poj2282(数位dp)

题意:计算a-b中各个数字出现的个数: 解法:数位dp(思想都是先算1-b的个数,然后减掉1-a中的个数),1-9数字的计算和前边计算1的那一篇数位dp差不多,计算0时候要加一维表示前缀是否全是0: 代码: /****************************************************** * author:xiefubao *******************************************************/ #pragma comment

UVALive3261 UVA1640 POJ2282 HDU1663 ZOJ2392 The Counting Problem

Regionals 2004 >> Asia - Shanghai 问题链接:UVALive3261 UVA1640 POJ2282 HDU1663 ZOJ2392 The Counting Problem. 问题简述:输入m和n,计算m到n(包括m和n)之间各个数中包含多少个0-9数字. 问题分析:先分别计算0到m-1和0到n之间数的数字个数,结果=0到n之间数的数字个数-0到m-1之间数的数字个数.计算0到n之间数的数字个数时,先考虑1位数.2位数.......,在小于n的区间逐步统计.