【luogu2602】【bzoj1833】 [ZJOI2010]数字计数 [数位dp]
套用的写windy数时的数位dp模板 emmm其实还有很多种做法
f[i][j][k]表示填了i位数其最高位数字为j时数码k出现了多少次
注意在 和x的位数相同有一位比x的对应位数小的全部方案数 其余位数对应数字都相同 的时候要再统计一下前面的数用了多少次
有i位数字的情况下 如果不考虑前导0,对于每一个数它们的数量都是相等的,也就是f[i]=f[i-1]*10+10^(i-1)
然后其他大致就是数位dp模板一样了
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<cstring> 5 #include<cmath> 6 #include<stack> 7 #include<algorithm> 8 using namespace std; 9 #define ll long long 10 #define rg register 11 const int N=2000000000+5,pw=11,inf=0x3f3f3f3f,P=19650827; 12 ll a,b; 13 ll base[20],f[20][10][10]; 14 ll ans[10][2]; 15 template <class t>void rd(t &x) 16 { 17 x=0;int w=0;char ch=0; 18 while(!isdigit(ch)) w|=ch=='-',ch=getchar(); 19 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); 20 x=w?-x:x; 21 } 22 23 void pre(){ 24 base[0]=1ll; 25 for(int i=1;i<=13;++i) base[i]=base[i-1]*10ll; 26 for(int i=0;i<=9;++i) f[1][i][i]=1ll; 27 for(int i=2;i<=13;++i)//填了i个 28 for(int j=0;j<=9;++j)//最高位 29 { 30 for(int k=0;k<=9;++k){ 31 for(int l=0;l<=9;++l) 32 f[i][j][l]+=f[i-1][k][l];} 33 f[i][j][j]+=base[i-1]; 34 } 35 } 36 37 void solve(ll x,int y){ 38 ll p=0,pre=x,num[20]; 39 // for(p=0;p<=13;++p) if(base[p]>x) break; 40 while(x) num[++p]=x%10,x/=10; 41 if(!p) return; 42 for(int i=1;i<p;++i) 43 for(int j=1;j<=9;++j) 44 for(int k=0;k<=9;++k) ans[k][y]+=f[i][j][k]; 45 for(int i=1;i<num[p];++i) 46 for(int j=0;j<=9;++j) ans[j][y]+=f[p][i][j]; 47 for(int i=p-1;i>0;--i){ 48 for(int j=0;j<num[i];++j) 49 for(int k=0;k<=9;++k) ans[k][y]+=f[i][j][k]; 50 for(int j=p;j>i;--j) 51 ans[num[j]][y]+=base[i-1]*num[i]; 52 } 53 } 54 int main() 55 { 56 //freopen("in.txt","r",stdin); 57 //freopen("nocows.out","w",stdout); 58 rd(a),rd(b); 59 pre(); 60 solve(a,0),solve(b+1,1); 61 for(int i=0;i<=9;++i) printf("%lld ",ans[i][1]-ans[i][0]); 62 return 0; 63 }