• bzoj 1833 [ZJOI2010]count 数字计数(数位DP)


    【题目链接】

        http://www.lydsy.com/JudgeOnline/problem.php?id=1833

    【题意】

        统计[a,b]区间内各数位出现的次数。

    【思路】

        设f[i][j][k]表示i位数,最高位为j,数位k出现的次数,则有递推式:

            f[i][j][k]=sigma{ f[i-1][l][k] ,0<=l<=9 } + 10^(i-1)

        第一项统计的是i-1位数中k的出现次数,后一项统计的是最高位k的出现数目。

        将查询差分,对于一个数,先统计长度不超过len的,再统计长度=len但最高位比a[len]小的,再统计长度为len且最高位为a[len]的。

        注意最后一项的统计,假设n为4321,我们要统计的就是:

            4000..4299

            4300..4319

            4320..4321

        假设我们要统计4000..4299,则有;

            ans[k]+=f[3][3][k]

            ans[4]+=321+1

    【代码】

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #define FOR(a,b,c) for(int a=b;a<=c;a++)
     5 using namespace std;
     6 
     7 typedef long long ll;
     8 const int N = 25;
     9 
    10 struct Node{
    11     ll a[N];
    12     Node() {
    13         memset(a,0,sizeof(a));
    14     }
    15     ll& operator[] (const int& x) {
    16         return a[x];
    17     }
    18 }; 
    19 Node operator + (const Node& x,const Node& y) {
    20     Node tmp;
    21     FOR(i,0,9) tmp.a[i]=x.a[i]+y.a[i];
    22     return tmp;
    23 }
    24 
    25 int len,a[N];
    26 ll e[N]; Node f[N][N];
    27 
    28 void init(ll n) 
    29 {
    30     len=0;
    31     while(n) {
    32         a[++len]=n%10;
    33         n/=10;
    34     }
    35     FOR(i,0,9) f[1][i][i]=1;
    36     FOR(i,2,14) FOR(j,0,9) {
    37         FOR(k,0,9)
    38             f[i][j]=f[i][j]+f[i-1][k];
    39         f[i][j][j]+=e[i-1];
    40     }
    41 }
    42 Node calc(ll n) 
    43 {
    44     Node ans;
    45     if(!n) return ans;
    46     memset(f,0,sizeof(f));
    47     init(n);
    48     FOR(i,1,len-1) FOR(j,1,9)
    49         ans=ans+f[i][j];
    50     FOR(i,1,a[len]-1) ans=ans+f[len][i];
    51     n%=e[len-1];
    52     ans[a[len]]+=n+1;
    53     for(int i=len-1;i;i--) {
    54         for(int j=0;j<a[i];j++) ans=ans+f[i][j];
    55         n%=e[i-1];
    56         ans[a[i]]+=n+1;
    57     }
    58     return ans;
    59 }
    60 
    61 int main()
    62 {
    63     e[0]=1;
    64     FOR(i,1,14) e[i]=e[i-1]*10ll;
    65     ll x,y;
    66     scanf("%lld%lld",&x,&y);
    67     Node ans1=calc(y) , ans2=calc(x-1);
    68     FOR(i,0,8) printf("%lld ",ans1[i]-ans2[i]);
    69     printf("%lld
    ",ans1[9]-ans2[9]);
    70     return 0;
    71 }
  • 相关阅读:
    英语口语练习系列-C15-心情不好
    英语口语练习系列-C14-常用片语
    英语口语练习系列-C13-聚会
    英语口语练习系列-C12-不了解
    英语口语练习系列-C11-了解
    Python3基础-分数运算
    英语口语练习系列-C10-up and down
    Python3基础系列-程序模板及代码本质
    英语口语练习系列-C09-常用动词
    英语口语练习系列-C08-考试
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5283425.html
Copyright © 2020-2023  润新知