【BZOJ-1833】count数字计数 数位DP
1833: [ZJOI2010]count 数字计数
Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 2494 Solved: 1101
[Submit][Status][Discuss]
Description
给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。
Input
输入文件中仅包含一行两个整数a、b,含义如上所述。
Output
输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。
Sample Input
1 99
Sample Output
9 20 20 20 20 20 20 20 20
20
HINT
30%的数据中,a<=b<=10^6;
100%的数据中,a<=b<=10^12。
Source
Solution
裸的数位DP,但其实并不是特别的水
首先F[i][j][k]表示位数为i的最高位为j的k种数的个数
按照十进制拆分,预处理后统计答案
Code
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; long long L,R; long long F[15][10][10],ans1[10],ans2[10]; void prework() { for (int i=0; i<=9; i++) F[1][i][i]=1; long long tmp=1; for (int i=2; i<=12; i++) { tmp*=10; F[i][0][0]=F[i-1][1][0]*9+F[i-1][0][0]+tmp; for (int j=1; j<=9; j++) F[i][0][j]=F[i-1][0][j]*9+F[i-1][j][j]; for (int j=1; j<=9; j++) { F[i][j][0]=F[i-1][1][0]*9+F[i-1][0][0]; for (int k=1; k<=9; k++) if (j==k) F[i][j][k]=F[i-1][0][k]*9+F[i-1][k][k]+tmp; else F[i][j][k]=F[i-1][0][k]*9+F[i-1][k][k]; } } } long long cf(int x) { long long re=1; for (int i=1; i<x; i++) re*=10; return re; } void Calc(long long x,long long *ans) { int digit[15]={0},len=0; long long y=x; while (x) {digit[++len]=x%10; x/=10;} for (int i=1; i<len; i++) for (int j=1; j<=9; j++) for (int k=0; k<=9; k++) ans[k]+=F[i][j][k]; for (int i=len; i>=1; i--) { for (int j=0; j<=digit[i]-1; j++) { if (i==len && j==0) continue; for (int k=0; k<=9; k++) ans[k]+=F[i][j][k]; } ans[digit[i]]+=y%cf(i)+1; } } int main() { prework(); scanf("%lld%lld",&L,&R); Calc(L-1,ans1); Calc(R,ans2); printf("%lld",ans2[0]-ans1[0]); for (int i=1; i<=9; i++) printf(" %lld",ans2[i]-ans1[i]); return 0; }
自己一开始YY的出错了..
——It's a lonely path. Don't make it any lonelier than it has to be.