洛谷 P2602 [ZJOI2010]数字计数
比较普通的数位DP,有个要注意的地方就是状态应该要是2维的
dp[i][j]表示前i位个数为j的数量,这样的话,后续加上去一位数字之后才能统计到之前本来就有的。
另外开两维,一维是表示统计的数字,还有一维标记前导零。
下附代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 ll dp[20][20][15][2]; 5 ll dim[20],resl[20],resr[20]; 6 ll dfs(int x,ll sum,int jb,int num,int fz){ 7 if (!x){ 8 return sum; 9 } 10 if (!jb && dp[x][sum][num][fz]!=-1) return dp[x][sum][num][fz]; 11 int maxn=9; 12 ll ret=0; 13 if (jb) maxn=dim[x]; 14 for (int i=0; i<=maxn; i++){ 15 if (fz==1){ 16 if (i==0) ret+=dfs(x-1,sum,(jb==1 && maxn==i),num,1); 17 else if (i==num) ret+=dfs(x-1,sum+1,(jb==1 && maxn==i),num,0); 18 else ret+=dfs(x-1,sum,(jb==1 && maxn==i),num,0); 19 } 20 else { 21 if (i==num) ret+=dfs(x-1,sum+1,(jb==1 && maxn==i),num,0); 22 else ret+=dfs(x-1,sum,(jb==1 && maxn==i),num,0); 23 } 24 25 } 26 if (!jb) return dp[x][sum][num][fz]=ret; 27 return ret; 28 } 29 int main(){ 30 memset(dp,-1,sizeof(dp)); 31 ll a,b; 32 scanf("%lld%lld",&a,&b); 33 a--; 34 int len=0; 35 while (a){ 36 dim[++len]=a%10; 37 a=a/10; 38 } 39 for (int i=0; i<=9; i++){ 40 resl[i]=dfs(len,0,1,i,1); 41 } 42 len=0; 43 while (b){ 44 dim[++len]=b%10; 45 b=b/10; 46 } 47 for (int i=0; i<=9; i++){ 48 resr[i]=dfs(len,0,1,i,1); 49 } 50 for (int i=0; i<=9; i++) 51 printf("%lld ",resr[i]-resl[i]); 52 }