题目链接:https://www.luogu.com.cn/problem/P2602
这道题大意是求某区间内数字0-9出现的次数。
分别统计区间内存在1个1,2个1,3个1……的数的个数,存在1个2,2个2,……,1个9,2个9,……的数的个数,然后求累加:累加的是次数*个数。
注意前导0和DFS最后的边界的处理。
num:哪一个数码 cnt:次数 now:已出现的次数
dp第一维记录pos,第二维记录now,第三维记录cnt,里面存ans。
AC代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 typedef long long ll; 7 ll dp[20][20][20],ans[50]; 8 int a[50]; 9 ll DFS(int pos,int now,int limit,int lead,int cnt,int num){ 10 if(pos==0) return now==cnt;//注意边界处理 11 if(!limit&&!lead&&dp[pos][now][cnt]!=-1) return dp[pos][now][cnt]; 12 int up=limit?a[pos]:9; 13 ll ans=0; 14 for(int i=0;i<=up;i++){ 15 if(lead&&i==0) ans+=DFS(pos-1,now,limit&&i==a[pos],1,cnt,num); 16 else ans+=DFS(pos-1,now+(i==num),limit&&i==a[pos],0,cnt,num); 17 } 18 if(!lead&&!limit) dp[pos][now][cnt]=ans; 19 return ans; 20 } 21 void solve(ll x,int flag){ 22 int len=0; 23 memset(dp,-1,sizeof(dp)); 24 while(x){ 25 a[++len]=x%10; 26 x/=10; 27 } 28 for(int i=0;i<=9;i++){ 29 for(int j=1;j<=len;j++){//枚举出现的次数 30 if(flag) ans[i]+=j*DFS(len,0,1,1,j,i); 31 else ans[i]-=j*DFS(len,0,1,1,j,i); 32 } 33 } 34 } 35 int main(){ 36 ll n,m; 37 scanf("%lld%lld",&n,&m); 38 solve(n-1,0); solve(m,1); 39 for(int i=0;i<=9;i++) printf("%lld ",ans[i]); 40 return 0; 41 }