您的位置:首页 > 其它

BZOJ_1833_[ZJOI2010]count 数字计数_数位DP

2018-03-04 22:39 561 查看

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]

; } } 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)); } }

[p] 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: