数字计数
题目链接:https://loj.ac/problem/10169
题意:给定两个正整数 l 和 r,求在[l,r]中的所有整数中,每个数字各出现了多少次。
思路:数位dp,维护每个数字出现次数和数字个数即可,在计数时,比如十位是1,那1的贡献还要加上个位所以可能的数。
#include<bits/stdc++.h> using namespace std; typedef long long ll; struct node { ll s; ll b[10]; node() { s=0; for(int i=0;i<10;i++) b[i]=0; } }dp[30]; int a[30]; //pos : 位数 qd : 是否为前导 flag : 是否处于上边界 node dfs(int pos,bool qd,bool flag) { if(pos==0) { node t; t.s=1; return t; } int up=flag?a[pos]:9;//确定上边界 if((!flag)&&(!qd)&&dp[pos].s)//如果之前已经求出,则直接返回 return dp[pos]; node tmp; tmp.s=0; for(int i=0;i<10;i++) tmp.b[i]=0; for(int i=0;i<=up;i++) { node t=dfs(pos-1,qd&&i==0,flag&&i==up); tmp.s+=t.s; for(int j=0;j<10;j++) tmp.b[j]+=t.b[j]; if(!qd || i!=0)//如果此时已经不是前导0,那i出现的次数要加上t.s tmp.b[i]+=t.s; } if((!flag)&&(!qd)) dp[pos]=tmp;//记录值,方便下次直接返回 return tmp; } node fun(ll x) { int pos=0; while(x)//将x的每一位进行分解 { a[++pos]=x%10; x/=10; } return dfs(pos,true,true); } int main() { ll l,r; cin>>l>>r; node x=fun(r); node y=fun(l-1); for(int i=0;i<10;i++) cout<<x.b[i]-y.b[i]<<" "; cout<<endl; }