学习了一波记忆化数位dp后写这题...我好像写的都跟大家的不一样???跑的还挺快的???(其实全世界一样都是0ms...)
题目大意:求[a,b]中0~9分别出现几次。(a,b<=10^12)
dp[pos][num][sum]表示前pos位,求num出现几次,这个数前pos位num已经出现sum次,前导零也很好处理,套记忆化模板就行了。
(太久没写博客了水一篇...(雾

#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #define ll long long using namespace std; ll dp[20][20][20],a[20],l,r; void read(ll &k) { k=0;ll f=1;char c=getchar(); while(c>'9'||c<'0')c=='-'&&(f=-1),c=getchar(); while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar(); k*=f; } ll dfs(int pos,int num,ll sum,bool lead,bool limit) { if(pos==0)return sum; if(!limit && !lead && dp[pos][num][sum]!=-1)return dp[pos][num][sum]; int up=limit?a[pos]:9; ll ans=0; if(!lead||pos==1)ans+=dfs(pos-1,num,sum+(num==0),0,limit && a[pos]==0); else ans+=dfs(pos-1,num,sum,1,limit && a[pos]==0); for(int i=1;i<=up;i++) ans+=dfs(pos-1,num,sum+(num==i),0,limit && a[pos]==i); if(!limit && !lead)dp[pos][num][sum]=ans; return ans; } ll solve(ll x,int num) { if(x<0)return 0; if(x==0)return num==0?1:0; int pos=0; while(x) { a[++pos]=x%10; x/=10; } return dfs(pos,num,0,1,1); } int main() { read(l);read(r); memset(dp,-1,sizeof(dp)); for(int i=0;i<=8;i++) printf("%lld ",solve(r,i)-solve(l-1,i)); printf("%lld ",solve(r,9)-solve(l-1,9)); }