BZOJ_1833_[ZJOI2010]count 数字计数_数位DP
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
之后按位枚举,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)); } }