[BZOJ1833][ZJOI2010]Count数字计数(DP)

数位DP学傻了,怎么写最后都写不下去了。

这题严格上来说应该不属于数位DP?只是普通DP加上一些统计上的判断吧。

首先复杂度只与数的位数$\omega$有关,所以怎么挥霍都不会超。

f[i][j][k]表示所有i位数(可以有前导零),第一位数为j,数字k出现的次数。直接$O(\omega^4)$转移即可。

接下来只需要统计[1,n]中某个数字出现的次数,分两种情况。

1. 第一位是0:这个直接做就好了。

2. 第一位不是0:枚举第一个小于原数的位置,同样直接转移。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=15;
 9 ll a,b,d[N],bin[N],f[N][N][N],res[N];
10 
11 void solve(ll x,int flag){
12     int len=0; ll tt=x;
13     memset(d,0,sizeof(d));
14     while (x) d[++len]=x%10,x/=10;
15     rep(i,1,len-1) rep(j,1,9) rep(k,0,9) res[k]+=f[i][j][k]*flag;
16     for (int tmp=len; tmp; tmp--){
17         rep(i,(tmp==len),d[tmp]-1)
18             rep(j,0,9) res[j]+=f[tmp][i][j]*flag;
19         res[d[tmp]]+=(tt%bin[tmp]+1)*flag;
20     }
21 }
22 
23 int main(){
24     freopen("bzoj1833.in","r",stdin);
25     freopen("bzoj1833.out","w",stdout);
26     scanf("%lld%lld",&a,&b);
27     bin[1]=1;
28     rep(i,2,13) bin[i]=bin[i-1]*10;
29     rep(i,0,9) f[1][i][i]=1;
30     rep(i,2,13) rep(j,0,9) rep(k,0,9){
31         rep(p,0,9) f[i][j][p]+=f[i-1][k][p];
32         f[i][k][k]+=bin[i-1];
33     }
34     solve(b,1); solve(a-1,-1);
35     rep(i,0,9) printf("%lld ",res[i]);
36     return 0;
37 }

 

posted @ 2018-07-08 09:04  HocRiser  阅读(278)  评论(0编辑  收藏  举报