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

1833: [ZJOI2010]count 数字计数

Time Limit: 3 Sec  Memory Limit: 64 MB
Submit:
2494  Solved: 1101
[Submit][Status][Discuss]

Description

给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。

Input

输入文件中仅包含一行两个整数a、b,含义如上所述。

Output

输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。

Sample Input

1 99

Sample Output

9 20 20 20 20 20 20 20 20
20

HINT

30%的数据中,a<=b<=10^6;
100%的数据中,a<=b<=10^12。

Source

Day1

Solution

裸的数位DP,但其实并不是特别的水

首先F[i][j][k]表示位数为i的最高位为j的k种数的个数

按照十进制拆分,预处理后统计答案

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
long long L,R;
long long F[15][10][10],ans1[10],ans2[10];
void prework()
{
    for (int i=0; i<=9; i++) F[1][i][i]=1;
    long long tmp=1;
    for (int i=2; i<=12; i++)
        {
            tmp*=10;
            F[i][0][0]=F[i-1][1][0]*9+F[i-1][0][0]+tmp;
            for (int j=1; j<=9; j++)
                F[i][0][j]=F[i-1][0][j]*9+F[i-1][j][j];
            for (int j=1; j<=9; j++)
                {
                    F[i][j][0]=F[i-1][1][0]*9+F[i-1][0][0];
                    for (int k=1; k<=9; k++)
                        if (j==k)
                            F[i][j][k]=F[i-1][0][k]*9+F[i-1][k][k]+tmp;
                        else
                            F[i][j][k]=F[i-1][0][k]*9+F[i-1][k][k];
                }
        }
}
long long cf(int x)
{
    long long re=1;
    for (int i=1; i<x; i++)
        re*=10;
    return re;
}
void Calc(long long x,long long *ans)
{
    int digit[15]={0},len=0; long long y=x;
    while (x) {digit[++len]=x%10; x/=10;}
    for (int i=1; i<len; i++)
        for (int j=1; j<=9; j++)
            for (int k=0; k<=9; k++)
                ans[k]+=F[i][j][k];
    for (int i=len; i>=1; i--)
        {
            for (int j=0; j<=digit[i]-1; j++)
                {
                    if (i==len && j==0) continue;
                    for (int k=0; k<=9; k++) ans[k]+=F[i][j][k];
                }
            ans[digit[i]]+=y%cf(i)+1;
        }
}
int main()
{
    prework();
    scanf("%lld%lld",&L,&R);
    Calc(L-1,ans1); Calc(R,ans2);
    printf("%lld",ans2[0]-ans1[0]);
    for (int i=1; i<=9; i++) printf(" %lld",ans2[i]-ans1[i]);
    return 0;
}

自己一开始YY的出错了..

时间: 2024-11-23 04:18:25

【BZOJ-1833】count数字计数 数位DP的相关文章

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>

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

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 数字计数(数位DP)

经典数位DP模板题. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # 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) 然后按

BZOJ 1833: [ZJOI2010]count 数字计数( dp )

dp(i, j, k)表示共i位, 最高位是j, 数字k出现次数. 预处理出来. 差分答案, 对于0~x的答案, 从低位到高位进行讨论 ------------------------------------------------------------------------------ #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 16; const int N =

【BZOJ 1833】 [ZJOI2010]count 数字计数

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