1. 程式人生 > >BZOJ_1833_[ZJOI2010]count 數字計數_數位DP

BZOJ_1833_[ZJOI2010]count 數字計數_數位DP

top string ffffff using zjoi2010 esp gpo height san

BZOJ_1833_[ZJOI2010]count 數字計數_數位DP

題意:

給定兩個正整數a和b,求在[a,b]中的所有整數中,每個數碼(digit)各出現了多少次。

分析:

數位DP

f[i][j][k]表示i位數,以j開頭的數中k出現的次數

預處理出來10的冪(在數位DP中經常會用到)

f[i][j][k]+=f[i-1][l][k]+(j==k)*10^(i-1)

之後按位枚舉,0的情況特殊處理

代碼:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL long long
LL f[15][11][11],a,b,mi[15];
void init(){
    mi[1]=1;
    for(int i=2;i<=13;i++){
        mi[i]=mi[i-1]*10;
    }
    for(int i=0;i<=9;i++){
        f[1][i][i]=1;
    }
    for(int i=2;i<=13;i++){
        for(int j=0;j<=9;j++){
            for(int k=0;k<=9;k++){
                for(int l=0;l<=9;l++){
                    f[i][j][k]+=f[i-1][l][k];
                    if(j==k)f[i][j][k]+=mi[i-1];
                }
            }
        }
    }
}
LL calc(LL x,int p){
    if(!x)return (!p);
    LL re=0;
    int d=13;
    while(mi[d]>x)d--;
    //d++;
    for(int i=1;i<d;i++){
        for(int j=1;j<=9;j++){
            re+=f[i][j][p];
        }
    }
    if(!p)re++;
    int cur=x/mi[d];
    for(int i=1;i<cur;i++){
            re+=f[d][i][p];
    }
    x%=mi[d];
    if(cur==p)re+=x+1;
    for(int i=d-1;i;i--){
        cur=x/mi[i];
        for(int j=0;j<cur;j++){
            re+=f[i][j][p];
        }
        x%=mi[i];
        if(cur==p)re+=x+1;
    }
    return re;
}
int main(){
    scanf("%lld%lld",&a,&b);
    init();
    int flg=0;
    for(int i=0;i<=9;i++){
        if(!flg)flg=
            printf("%lld",calc(b,i)-calc(a-1,i));
        else printf(" %lld",calc(b,i)-calc(a-1,i));
    }
}

技術分享圖片

BZOJ_1833_[ZJOI2010]count 數字計數_數位DP