BZOJ1833: [ZJOI2010]count 数字计数
【传送门:BZOJ1833】
简要题意:
给出l,r,求出l到r中0到9的数字出现的次数
题解:
数位DP,设f[i][j][k]为i位数,最高位为j,k出现的次数
需要注意一下前导零的问题
参考代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> using namespace std; typedef long long LL; LL f[13][10][10];//第i位为j时,有多少个k LL cf(int b) { LL a=10,ans=1; while(b!=0) { if(b%2==1) ans*=a; a*=a;b/=2; } return ans; } void getdp() { for(int i=0;i<=9;i++) f[1][i][i]=1; for(int i=2;i<=12;i++) { for(int j=0;j<=9;j++) { for(int k=0;k<=9;k++) { if(j==k) f[i][j][k]=cf(i-1); for(int t=0;t<=9;t++) f[i][j][k]+=f[i-1][t][k]; } } } } int a[13],cnt; LL ans[11]; void solve(LL d,int t) { cnt=0;LL sum=d; if(d!=0) ans[0]+=t*1; while(d!=0) { a[++cnt]=d%10; d/=10; } for(int i=1;i<cnt;i++) { for(int j=1;j<=9;j++) { for(int k=0;k<=9;k++) ans[k]+=t*f[i][j][k];//位数小,无前导零 } } for(int i=1;i<a[cnt];i++) { for(int j=0;j<=9;j++) ans[j]+=t*f[cnt][i][j];//最高位且不为零 } sum-=a[cnt]*cf(cnt-1); ans[a[cnt]]+=t*(sum+1); for(int i=cnt-1;i>=1;i--) { for(int j=0;j<a[i];j++) { for(int k=0;k<=9;k++) ans[k]+=t*f[i][j][k]; } sum-=a[i]*cf(i-1); ans[a[i]]+=t*(sum+1); } } int main() { getdp(); LL a,b; scanf("%lld%lld",&a,&b); solve(a-1,-1); solve(b,1); for(int i=0;i<9;i++) printf("%lld ",ans[i]); printf("%lld\n",ans[9]); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚