标签:数位 clu 有一个 mil pac amp code i++ inpu
给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。
输入文件中仅包含一行两个整数a、b,含义如上所述。
输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。
1 99
9 20 20 20 20 20 20 20 20 20
30%的数据中,a<=b<=10^6;
100%的数据中,a<=b<=10^12。
【解题思路】
关于数位dp,(数位dp的题只有dfs才是通解) 个人认为dfs代码要比递推的代码简洁不少,而且更易理解。
题解已经有一个四维的dfs了,实际上这个题数组只需要开两维,可以省掉两维,于是发一个二维的。
先说下思路,对于这道数位dp的水题我们考虑用记忆化搜索来解决。定义num数组来拆数,显然需要bool limit和lead来分别判断是否达有限制和是否有前导0。有前导0设为0,有限制为1。具体请看代码。
【code】
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 using namespace std;
6 long long a , b;
7 long long dp[20][20],num[20];
8 long long dfs(int pos,bool limit,bool lead,int dig,long long sum)
9 //sum是一定需要存的一个变量,因为她表示的是操作答案,需要不断随dfs更新
10 {//limit为1表示有限制,lead为0表示有前导0
11 long long ans=0;
12 if (pos==0) return sum;//边界条件
13 if(!limit&&lead&&dp[pos][sum]!=-1) return dp[pos][sum];//记忆化
14 int up=9;
15 if(limit) up=num[pos];//达到限制就设上限为当前位的数(不想用三目运算符)(雾)
16 for(int j=0;j<=up;j++)
17 ans+=dfs(pos-1, (j==up)&&limit , lead||j , dig , sum+((j||lead)&&(j==dig)) );
18 if(!limit&&lead) dp[pos][sum]=ans;
19 return ans;
20 }//数位dp的操作
21 long long work(long long x,int d)
22 {
23 memset(dp,-1,sizeof(dp));//初始化
24 int len=0;
25 while(x)
26 {
27 num[++len]=x%10;//最高位在第一位
28 x/=10;
29 }
30 return dfs(len,1,0,d,0);
31 }
32 int main()
33 {
34 cin>>a>>b;
35 for(int i=0;i<=9;i++)//九个digit
36 {
37 if(i!=9)cout<<work(b,i)-work(a-1,i)<<" ";
38 else cout<<work(b,i)-work(a-1,i);
39 //我也不知道最后边输出了空格会不会炸(手动滑稽)
40 }
41 return ^-^;
42 }
标签:数位 clu 有一个 mil pac amp code i++ inpu
原文地址:https://www.cnblogs.com/66dzb/p/11247134.html