bzoj1833: [ZJOI2010]count 数字计数(数位DP+记忆化搜索)

1833: [ZJOI2010]count 数字计数

题目:传送门 

 


 

 

题解:

   今天是躲不开各种恶心DP了???

   %爆靖大佬啊!!!

   据说是数位DP裸题...emmm学吧学吧

   感觉记忆化搜索特别强:

   定义f[i][j][k]表示若前i个位置有k个j的此时的全局方案数,然后就可以记忆化搜索了(具体看代码吧)

    


 

 

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 typedef long long LL;
 8 LL f[15][11][15],a[15];
 9 LL n,m;
10 LL dfs(int pos,int x,int sum,bool ld,bool lt)//ld表示当前情况是否要考虑前导0,lt表示的是枚举数字的上限是否有规定 
11 {
12     if(pos==0)return sum;
13     if(ld==false && lt==false && f[pos][x][sum]!=-1)return f[pos][x][sum];
14     LL up=9,ans=0;if(lt==true)up=a[pos];
15     for(int i=0;i<=up;i++)
16     {
17         int ss=sum;bool bk1=false,bk2=false;
18         if(i==x)ss++;
19         if(ld==true && i==0){bk1=true;if(x==0)ss--;}
20         if(lt==true && i==a[pos])bk2=true;
21         ans+=dfs(pos-1,x,ss,bk1,bk2);
22     }
23     if(ld==false && lt==false)f[pos][x][sum]=ans;
24     return ans;
25 }
26 LL sol(LL x,int y)
27 {
28     int pos=0;
29     while(x){a[++pos]=x%10;x/=10;}
30     return dfs(pos,y,0,1,1);
31 }
32 int main()
33 {
34     memset(f,-1,sizeof(f));
35     scanf("%lld%lld",&n,&m);
36     for(int i=0;i<9;i++)printf("%lld ",sol(m,i)-sol(n-1,i));
37     printf("%lld\n",sol(m,9)-sol(n-1,9));
38     return 0;
39 }

 

posted @ 2018-04-12 14:18  CHerish_OI  阅读(312)  评论(0编辑  收藏  举报