首页 > 代码库 > 【Dream Counting, 2006 Dec-数数的梦】数位dp
【Dream Counting, 2006 Dec-数数的梦】数位dp
题意:给定两个数,问区间[A,B]中0~9分别出现了多少次。A,B<=10^18
题解:应该是最裸的数位dp吧。。一开始没有记忆化tle了TAT
我们可以求出区间[0,B]的,再减去区间[0,A]的。
用dfs实现,记录flag(填了的位是否和边界重合),zero(当前是否还在前缀0中)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<iostream>
5 #include<ctime>
6 #include<queue>
7 using namespace std;
8
9 typedef long long LL;
10 const int N=100;
11 int c[N][N][2][2],d[N],sum[N];
12 LL bit[N],ret[N];
13
14 LL g(int now,int x,int flag,int zero)
15 {
16 if(c[now][x][flag][zero]!=-1) return c[now][x][flag][zero];
17 if(x==0) return 0;
18 LL ans=0;
19 if(flag)
20 {
21 for(int i=0;i<d[x];i++)
22 {
23 ans+=g(now,x-1,0,zero & (i==0));
24 if(i==now && !(i==0 && zero)) ans+=bit[x-1];
25 }
26 ans+=g(now,x-1,1,zero && (d[x]==0));
27 if(now==d[x] && !(now==0 && zero)) ans+=ret[x-1];
28 }
29 else
30 {
31 for(int i=0;i<=9;i++)
32 {
33 ans+=g(now,x-1,0,zero & (i==0));
34 if(i==now && !(i==0 && zero)) ans+=bit[x-1];
35 }
36 }
37 // printf("now %d x %d flag %d zero %d = %d\n",now,x,flag,zero,ans);
38 c[now][x][flag][zero]=ans;
39 return ans;
40 }
41
42 void solve(LL x,LL tmp)
43 {
44 memset(d,0,sizeof(d));
45 memset(c,-1,sizeof(c));
46 int l=0;LL y=x;
47 while(y)
48 {
49 d[++l]=(int)(y%10);
50 y/=10;
51 }
52 for(int i=0;i<=18;i++) ret[i]=x%bit[i]+1;
53 for(int i=0;i<=9;i++) sum[i]+=g(i,20,1,1)*tmp;
54 }
55
56 int main()
57 {
58 // freopen("a.in","r",stdin);
59 freopen("dream.in","r",stdin);
60 freopen("dream.out","w",stdout);
61 LL A,B;int x;
62 scanf("%lld%lld",&A,&B);
63 memset(sum,0,sizeof(sum));
64 bit[0]=1;
65 for(int i=1;i<=18;i++) bit[i]=bit[i-1]*10;
66 solve(A-1,-1);
67 solve(B,1);
68 for(int i=0;i<=9;i++) printf("%d ",sum[i]);
69 return 0;
70 }
【Dream Counting, 2006 Dec-数数的梦】数位dp
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。