BZOJ 1833 数字计数(数位DP)

经典数位DP模板题。

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-9
# define MOD 1024523
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
void Out(int a) {
    if(a<0) {putchar(‘-‘); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+‘0‘);
}
const int N=55;
//Code begin...

LL dp[10][15][10], p[15], d[15];
int wei[15];

LL dfs(int pos, int pre, int limit, int lead, int x){
    if (pos==0) return pre==x;
    if (!limit&&!lead&&~dp[x][pos][pre]) return dp[x][pos][pre];
    int up=limit?wei[pos]:9;
    LL res=0;
    if (x||!lead) {
        if (pre==x) {
            if (limit) res+=d[pos]+1;
            else res+=p[pos];
        }
    }
    FOR(i,0,up) res+=dfs(pos-1,i,limit&&i==wei[pos],lead&&i==0,x);
    if (!limit&&!lead) dp[x][pos][pre]=res;
    return res;
}
LL sol(int x, LL val){
    int pos=0;
    while (val) wei[++pos]=val%10, val/=10, d[pos]=wei[pos]*p[pos-1]+d[pos-1];
    return dfs(pos,0,1,1,x);
}
int main ()
{
    LL a, b;
    mem(dp,-1);
    p[0]=1; FOR(i,1,15) p[i]=p[i-1]*10;
    scanf("%lld%lld",&a,&b);
    FO(i,0,10) printf(i==0?"%lld":" %lld",sol(i,b)-sol(i,a-1));
    putchar(‘\n‘);
    return 0;
}

时间: 2024-12-24 11:24:16

BZOJ 1833 数字计数(数位DP)的相关文章

BZOJ 1833 数字计数(统计[a,b]每个数字出现次数)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1833 题意:给定区间[a,b].求区间内0到9每个数字出现的次数. 思路:f[i][j]表示到后i位是否全 0(j=1表示i位之前全0)这个状态某个数字出现的次数,p[i][j]表示这个状态后面有多少个数字.那么当前枚举到的数字为要统计的数字时,答案加 上后面还有多少种数字,即下一个状态的p值.那么我们枚举要统计的数字依次统计即可. i64 f[20][2],p[20][2]; i64

BZOJ 1833 ZJOI 2010 count 数字计数 数位DP

题目大意:问0~9这10个数字在[l,r]中出现过多少次. 思路:数位DP.以前只是听说过,并没有写过,写了才发现好闹心啊.. 预处理一个数组,f[i][j][k]表示长度为i,开头为j,数字k出现的次数. 对于一个数kXXXXXX,我们先处理1~999999,然后处理1000000~kXXXXXX 前面的东西很规则,可以直接调用f数组来解决. 对于后面不太规则的东西,按位处理.总之就是乱搞,我也不太懂说不明白... CODE: #include <cstdio> #include <c

【BZOJ-1833】count数字计数 数位DP

1833: [ZJOI2010]count 数字计数 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 2494  Solved: 1101[Submit][Status][Discuss] Description 给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次. Input 输入文件中仅包含一行两个整数a.b,含义如上所述. Output 输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次.

bzoj1833: [ZJOI2010]count 数字计数(数位DP+记忆化搜索)

1833: [ZJOI2010]count 数字计数 题目:传送门 题解: 今天是躲不开各种恶心DP了??? %爆靖大佬啊!!! 据说是数位DP裸题...emmm学吧学吧 感觉记忆化搜索特别强: 定义f[i][j][k]表示若前i个位置有k个j的此时的全局方案数,然后就可以记忆化搜索了(具体看代码吧) 代码: 1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath>

BZOJ1833: [ZJOI2010]count 数字计数 (数位dp)

传送门 数位dp... ...大概都是这个套路吧... ... 写这个的时候直接水了一发... ...我也不知道自己写的是不是dp... ... 大概是主要内容和dp关系不大的dp... ... mark代码..细长的代码真是丑啊..换行太频繁了.... 1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm&g

BZOJ 1833 ZJOI2010 count 数字计数 数位DP

题目大意:求[a,b]间所有的整数中0~9每个数字出现了几次 令f[i]为i位数(算前导零)中每个数出现的次数(一定是相同的,所以只记录一个就行了) 有f[i]=f[i-1]*10+10^(i-1) 然后照例十进制拆分 其中计算[0,999...9]的时候要从1~9枚举最高位,然后其余位调用f[i-1]即可 剩余部分已知位直接乘,未知位调用f[i] #include<cstdio> #include<cstring> #include<iostream> #includ

bzoj 1833 数字计数

题目大意: 给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次 思路: 不知道黄学长他们的dp都是怎么dp的 搞神的方法太强啦 %%% 数位乱搞.. 推了公式,然后每一位直接套用公式 每一位分3种情况 小于该位数字的直接+10的位数次方 等于的+10的位数减一次方再加上后面几位构成数字那么多 大于的+10的位数减一次方 1 #include<iostream> 2 #include<cstdio> 3 #include<cmath>

题解——[ZJOI2010]数字计数 数位DP

最近在写DP,今天把最近写的都放上来好了,,, 题意:给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次. 首先询问的是一个区间,显然是要分别求出1 ~ r ,1 ~ l的答案,然后相减得到最终答案 首先我们观察到,产生答案的区间是连续的,且可以被拆分, 也就是说0 ~ 987的贡献= 0 ~ 900 + 901 ~ 987的恭喜, 同理,把位拆开也是等价的,所以我们可以单独计算每个位的贡献 这样讲可能有点不太清晰,举个例子吧 3872 我们先把它按数拆开来

【BZOJ1833】【ZJOI2010】数字计数 数位DP

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46444975"); } 题解: 然而并没有DP. [1,R]的答案减去[1,L]的答案. 对于一个数 X ,求 [1,X] 的答案,我是先处理出 [1,999--9] 的答案(那个999--9 < X) 然后按