UVA 1640 The Counting Problem
https://vjudge.net/problem/UVA-1640
题意:统计区间[l,r]中0——9的出现次数
数位DP
注意删除前导0
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int ans[10],a[10],dp[10][10],bit[10]; int dfs(int dep,int ty,bool lim,int k) { if(!dep) return ty; if(!lim && dp[dep][ty]!=-1) return dp[dep][ty]; int ans=0,up= lim ? a[dep] : 9; for(int i=0;i<=up;i++) { if(i==k) ans+=dfs(dep-1,ty+1,lim && i==up,k); else ans+=dfs(dep-1,ty,lim && i==up,k); } if(!lim) dp[dep][ty]=ans; return ans; } int main() { int l,r; bit[1]=10; for(int i=2;i<=8;i++) bit[i]=bit[i-1]*10; while(scanf("%d%d",&l,&r)!=EOF) { if(!l) return 0; if(l>r) swap(l,r); memset(ans,0,sizeof(ans)); a[0]=0; while(r) a[++a[0]]=r%10,r/=10; for(int i=0;i<=9;i++) { memset(dp,-1,sizeof(dp)); ans[i]=dfs(a[0],0,1,i); } l--; if(!l) ans[0]--; int tmp=a[0]; a[0]=0; while(l) a[++a[0]]=l%10,l/=10; for(int i=0;i<=9;i++) { memset(dp,-1,sizeof(dp)); ans[i]-=dfs(a[0],0,1,i); } while(tmp!=a[0]) ans[0]-=bit[--tmp]; printf("%d",ans[0]); for(int i=1;i<=9;i++) printf(" %d",ans[i]); printf("\n"); } }
2.0:
直接在dp过程中计算前导0
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[21]; long long dp[21][21][2],ans[11]; long long dfs(int dep,int cnt,bool lim,int zero,int num) { if(!dep) return cnt; if(!lim && dp[dep][cnt][zero]!=-1) return dp[dep][cnt][zero]; int up=lim ? a[dep] : 9; long long ans=0; for(int i=0;i<=up;++i) ans+=dfs(dep-1,cnt+((i || !zero) && (i==num)),lim && i==up,zero && !i,num); if(!lim) dp[dep][cnt][zero]=ans; return ans; } void solve(long long n,int tag) { int len=0; while(n) { a[++len]=n%10; n/=10; } for(int i=0;i<=9;++i) { memset(dp,-1,sizeof(dp)); ans[i]+=tag*dfs(len,0,1,1,i); } } int main() { long long l,r; scanf("%lld%lld",&l,&r); if(l>r) swap(l,r); solve(r,1); solve(l-1,-1); for(int i=0;i<=9;++i) printf("%lld\n",ans[i]); }