BZOJ_1833_[ZJOI2010]count 數字計數_數位DP
阿新 • • 發佈:2018-03-05
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