BZOJ1833 [ZJOI2010]count 数字计数 【数学 Or 数位dp】

题目

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

输入格式

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

输出格式

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

输入样例

1 99

输出样例

9 20 20 20 20 20 20 20 20 20

提示

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

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

题解

你以为我真的会写数位dp?

首先容斥一下,转化为求小于等于n的方案数

如果不考虑前缀0,那么就只需要递归处理不大于n所有数字出现的次数

考虑前缀0,我们再减去开头有若干个0的方案数

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts("");
using namespace std;
const int maxn = 15,maxm = 100005,INF = 1000000000;
LL g[maxn],Pow[maxn];
void init(){
    Pow[0] = 1;
    for (int i = 1; i < maxn; i++) Pow[i] = Pow[i - 1] * 10;
    g[1] = 1;
    for (int i = 2; i < maxn; i++){
        g[i] = 10 * g[i - 1] + Pow[i - 1];
    }
}
struct node{
    LL t[10];
    node(){memset(t,0,sizeof(t));}
};
node cal(LL n,LL h,LL tmp){
    //cout << n << endl;
    node re,t;
    if (h == 1){
        for (int i = 0; i <= n; i++) re.t[i] = 1;
        return re;
    }
    for (int i = 0; i <= 9; i++){
        re.t[i] += (n / tmp) * g[h - 1];
        if (i < n / tmp) re.t[i] += Pow[h - 1];
    }
    re.t[n / tmp] += n - (n / tmp) * tmp + 1;
    t = cal(n % tmp,h - 1,tmp / 10);
    for (int i = 0; i <= 9; i++) re.t[i] += t.t[i];
    return re;
}
node solve(LL n){
    LL h = 1,tmp = 1;
    for (LL i = n; i / 10; i /= 10) h++,tmp *= 10;
    node re = cal(n,h,tmp);
    for (int i = 1; i < h; i++){
        re.t[0] -= Pow[h - i];
    }
    return re;
}
int main(){
    init();
    LL a,b;
    cin >> a >> b;
    node ansr = solve(b),ansl = solve(a - 1);
    for (int i = 0; i < 9; i++) printf("%lld ",ansr.t[i] - ansl.t[i]);
    printf("%lld",ansr.t[9] - ansl.t[9]);
    return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/8733863.html

时间: 2024-10-07 10:27:42

BZOJ1833 [ZJOI2010]count 数字计数 【数学 Or 数位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>

bzoj1833: [ZJOI2010]count 数字计数 &amp;&amp; codevs1359 数字计数

bzoj1833 codevs1359 这道题也是道数位dp 因为0有前导0这一说卡了很久 最后发现用所有位数减1~9的位数就okay.....orzczl大爷 其他就跟51nod那道统计1出现次数一样啦 #include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; LL read(){ LL ans=0,f=1,c=getchar();

数位DP入门:bzoj1833: [ZJOI2010]count 数字计数

膜拜了一下蔡大神....然后突然想起来一些东西然后就填了一个半年多前的坑= = 人生第一道自己写的数位DP...好吧以前是看题解然后也不知道为什么就过了的>_< 数位DP介绍: http://wenku.baidu.com/link?url=9OS5Ybpw5wx00ahrH8ED2oyIlR1uWwrxT8N4pEg27GgBt2T2hLe4sd_h1rmpY7P0HmeHIEDw9h6_K98dPhhjoMhD2TpKcS8w1X8cC_dkPp_ 接下来是题目地址: http://www

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

bzoj1833 [ZJOI2010]count 数字计数

题目链接 我是DP弱者!!!我是DP弱者!!!我是DP弱者!!! 调了好久,数位DP好恼火QAQ 1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<string> 7 #include<cmath> 8 #include<ctime> 9

【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]中出现了多少次.

1833: [ZJOI2010]count 数字计数

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

【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]中出现了多少次.

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 =