zoukankan      html  css  js  c++  java
  • [BZOJ] 1833: [ZJOI2010]count 数字计数

    1833: [ZJOI2010]count 数字计数

    Time Limit: 3 Sec  Memory Limit: 64 MB
    Submit: 3784  Solved: 1663
    [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

    Analysis

    数位动规模板题

    蒟蒻的数位动规之旅可谓艰辛qwq

    四处扒题解搞模板

    最后还是用的自己的诡异表示AC

    = =

    首先状态表示 DP[ len ] 表示长度为 len 的,额,数码串所有状态包含的单个数码的数量

    你看,如果不计算前导零的话,其实每个数码(0,1,2,3...)都是一样的

    十个数码的数量都是重复数据

    所以将前导零暂且扔掉,只储存指定长度的数码数量

    那么引入一个 Pow[ len ] ,你看,如果给一个指定的数码串再多加一位,那么多加的那一位会使数量增益个,,,额

    原来的数码串是形如 4357594 这样的 7 位长的

    那么我们增加第 8 位时,原来的排列并不会改变,但是会增加 0435... 1435... 2435... 等

    这样,填进第 8 位的数码就有 107 的增加量

    那么定义 Pow[ i ] = 10i-1

    就得到了 DP[ i ] = DP[ i-1 ] * 10 + Pow[ i ]

    以下为对代码的解释

    那么我们考虑这个数位动规的实质,它的实质就是对一棵类似字典树的东西计数,深度即长度

    那么用上面那种极其简单的DP表示,我们可以解决掉一棵完整的子树,却不能很好的处理形如 85 这种不能单纯用长度来计数的数字

    那么对于这种不完整子树,我们只要一层层往下处理就行了

    如上图,我们可以用 DP 直接统计掉第二层的 0 - 7 以及第三层的 0 - 4

    但是处于边界的 8 和 5 ... = =

    我们这样考虑

    用 DP 能够处理掉 8 左边的部分,那么 8 本身的答案对应到实际是这样的:

    80 81 82 83 84 85

    也就是,8 这棵树有多少叶子结点,他就有多少增益

    那么拿 85 减去前面计数过的叶子结点,就是 8 的增益了

    之后是前导零

    前导零在树中是这样子的:

    反而前导零比较容易处理

    每一层都给 0 的计数减去一个 Pow[ len ] 即可

    注意只有一位数的 0 是算数的,所以需要提前给 0 增加

    Code

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 
     5 long long Pow[20],DP[20],a,b;
     6 
     7 struct data{
     8     long long d[20];
     9     data(){ for(int i = 0;i < 20;i++) d[i] = 0;}
    10 };
    11 
    12 long long getlen(long long &x){
    13     long long ret = 0; for(long long i = x;i;i /= 10) ret++;
    14     return ret;
    15 }
    16 
    17 data conc(long long x){
    18     x++;
    19     long long dig[20] = {0},lenx = 0;
    20     data ans;
    21     if(!x) return ans;
    22     
    23     for(long long i = x;i;i /= 10)
    24         dig[lenx++] = i%10;
    25     
    26     ans.d[0]++;
    27     for(long long p = lenx-1;p >= 0;p--){
    28         ans.d[0] -= Pow[p+1];
    29         for(long long i = 0;i < dig[p];i++){
    30             ans.d[i] += Pow[p+1];
    31             for(long long j = 0;j <= 9;j++){
    32                 ans.d[j] += DP[p];
    33             }
    34         }x -= Pow[p+1]*dig[p];
    35         ans.d[dig[p]] += x;
    36     }
    37     return ans;
    38 }
    39 
    40 int main(){
    41     Pow[0] = Pow[1] = 1;
    42     for(long long i = 2;i <= 15;i++) Pow[i] = Pow[i-1]*10;
    43     
    44     scanf("%lld%lld",&a,&b);
    45     long long lena = getlen(a),lenb = getlen(b);
    46     
    47     DP[1] = 1;
    48     for(long long i = 2;i <= lenb+1;i++) DP[i] = DP[i-1]*10+Pow[i];
    49     
    50     data ret1 = conc(a-1);
    51     data ret = conc(b);
    52     
    53     for(long long i = 0;i <= 9;i++) 
    54         if(!i) printf("%lld",ret.d[i]-ret1.d[i]);
    55         else printf(" %lld",ret.d[i]-ret1.d[i]);
    56     
    57     return 0;
    58 }
    qwq
  • 相关阅读:
    flask的Request对象
    Spinner实现列表下拉功能
    ListView用法
    DatePickerDialog和TimePickerDialog(基于对话框显示时间和日期)
    DataPicker以及TimePicker显示时间和日期(屏幕上显示)
    Floyd-Warshall算法(最短路)
    Bellman-Ford算法(最短路)
    前向星
    css3变形与动画
    CSS3背景 background-size
  • 原文地址:https://www.cnblogs.com/Chorolop/p/7699091.html
Copyright © 2011-2022 走看看