zoukankan      html  css  js  c++  java
  • [ZJOI2010] 数字统计

    [ZJOI2010] 数字统计

    题目

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

    INPUT

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

    OUTPUT

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

    SAMPLE

    INPUT

    1 99

    OUTPUT

    9 20 20 20 20 20 20 20 20 20

    解题报告

    第二道数位$dp$,找着点感觉了?

    首先,我们预处理出来从低向高位数第$i$位数,每个数码出现的次数,递推式很简单

    $$f[i]=10*f[i-1]+10^{i-1}$$

    我们分两部分考虑即可,第$i$位为该数字的数有$10^{i-1}$个,后$i-1$位数该该数字出现的次数为$f[i-1]$,前面的数共有$10$种可能(允许前导0),故$f[i]=10*f[i-1]+10^{i-1}$

    然后考虑如何统计答案。

    对于低于该数位数的数,我们可以去除前导零,对上式进行变形(具体式子见代码),求和即可

    对于位数等于该数位数的数,我们可以逐位枚举统计,利用处理出来的$f$数组和$10^{i}$进行转移即可

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 using namespace std;
     5 typedef long long L;
     6 L a,b,f[20],pw[20],ans[20];
     7 int num[40],top;
     8 inline void solve(L x,int flag){
     9     if(!x)return;
    10     top=0;L ret(x);
    11     while(x){num[++top]=x%10;x/=10;}
    12     for(int i=1;i<top;++i)
    13         for(int j=0;j<=9;++j)
    14             ans[j]+=flag*(9*f[i-1]+(j?pw[i-1]:0));
    15     for(int i=top;i;--i){
    16         ret-=num[i]*pw[i-1];ans[num[i]]+=(ret+1)*flag;
    17         for(int j=(i==top);j<num[i];++j)ans[j]+=pw[i-1]*flag;
    18         for(int j=0;j<=9;++j)ans[j]+=f[i-1]*(num[i]-(i==top))*flag;
    19     }
    20 }
    21 int main(){
    22     freopen("countzj.in","r",stdin);freopen("countzj.out","w",stdout);
    23     scanf("%lld%lld",&a,&b);
    24     pw[0]=1;for(int i=1;i<=13;++i)f[i]=10*f[i-1]+pw[i-1],pw[i]=pw[i-1]*10;
    25     solve(b,1);solve(a-1,-1);
    26     printf("%lld",ans[0]);for(int i=1;i<=9;++i)printf(" %lld",ans[i]);
    27 }
    View Code
  • 相关阅读:
    移动端触摸右侧菜单栏,页面内容对应项滚动到最上方
    swiper使用中一些点的总结
    javaScript正则表达式入门
    javaScript之数组操作方法(一)
    初识vue
    焦点控制切换和轮播
    文本内容只显示两行,然后加...
    图片父容器高度不定的图片垂直居中
    css3图片垂直居中
    【C#】两个list根据某个元素比较差集
  • 原文地址:https://www.cnblogs.com/hzoi-mafia/p/7766435.html
Copyright © 2011-2022 走看看