hdu 3709+hdu 3555(数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3709

数位dp...完全看大牛模版理解的。。。。

View Code
 1 #include<iostream>
 2 using namespace std;
 3 __int64 dp[19][19][2000];
 4 int digit[19];
 5 
 6 //pos表示当前的位置,o表示支点,pre表示从最高位到pos的力矩之和,doing表示是否有上限,若无,则为9;
 7 __int64 dfs(int pos,int o,int pre,bool doing){
 8     if(pos==-1){
 9         return pre==0;  //已经全部组合
10     }
11     if(pre<0)return 0;//如果前面组合的力矩之和已经为负,则后面的必然小于0;
12     //没有上限,且前面的状态已经搜过
13     if(!doing&&dp[pos][o][pre]!=-1){
14         return dp[pos][o][pre];
15     }
16     __int64 ans=0;
17     int end=doing?digit[pos]:9;
18     for(int i=0;i<=end;i++){
19         int npre=pre;   //枚举下一个状态
20         npre+=(pos-o)*i;   
21         ans+=dfs(pos-1,o,npre,doing&&i==end);
22     }
23     if(!doing){
24         dp[pos][o][pre]=ans;
25     }
26     return ans;
27 }
28 
29 __int64 solve(__int64 n){
30     int pos=0;
31     while(n){
32         digit[pos++]=n%10;
33         n/=10;
34     }
35     __int64 ans=0;
36     for(int o=0;o<pos;o++){
37         ans+=dfs(pos-1,o,0,1);
38     }
39     return ans-(pos-1);//0,00,000....这种情况
40 }
41 
42 int main(){
43     int _case;
44     scanf("%d",&_case);
45     memset(dp,-1,sizeof(dp));
46     while(_case--){
47         __int64 n,m;
48         scanf("%I64d%I64d",&n,&m);
49         printf("%I64d\n",solve(m)-solve(n-1));
50     }
51     return 0;
52 }

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555

View Code
 1 #include<iostream>
 2 using namespace std;
 3 __int64 dp[20][3];
 4 int digit[20];
 5 
 6 //have==1表示前一位为4,have==0表示没有出现49,have==2表示前面有49出现
 7 __int64 dfs(int pos,int have,bool doing){
 8     if(pos==-1){
 9         return have==2;//找到一个解
10     }
11     if(!doing&&dp[pos][have]!=-1){
12         return dp[pos][have];
13     }
14     __int64 ans=0;
15     int end=doing?digit[pos]:9;
16     for(int i=0;i<=end;i++){
17         int nhave=have;
18         if(have==1&&i!=4){
19             nhave=0;
20         }
21         if(have==0&&i==4){
22             nhave=1;
23         }
24         if(have==1&&i==9){
25             nhave=2;
26         }
27         ans+=dfs(pos-1,nhave,doing&&i==end);
28     }
29     if(!doing)
30         dp[pos][have]=ans;
31     return ans;
32 }
33 
34 __int64 solve(__int64 n){
35     int pos=0;
36     while(n){
37         digit[pos++]=n%10;
38         n/=10;
39     }
40     return dfs(pos-1,0,1);
41 }
42 
43 int main(){
44     int _case;
45     scanf("%d",&_case);
46     memset(dp,-1,sizeof(dp));
47     while(_case--){
48         __int64 n;
49         scanf("%I64d",&n);
50         printf("%I64d\n",solve(n));
51     }
52     return 0;
53 }

昨天做的fzu的月赛。。。当时没过。。。

http://acm.fzu.edu.cn/contest/problem.php?cid=126&sortid=1

这个代码我没提交过。。。

View Code
 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 __int64 dp[20][20];
 5 int digit[20];
 6 
 7 __int64 DFS(int pos,int have,bool doing){
 8     if(pos==-1){
 9         return have;
10     }
11     if(!doing&&dp[pos][have]!=-1){
12         return dp[pos][have];
13     }
14     __int64 ans=0;
15     int end=doing?digit[pos]:9;
16     for(int i=0;i<=end;i++){
17         int nhave=have;
18         if(i==1)nhave=have+1;
19         ans+=DFS(pos-1,nhave,doing&&i==end);
20     }
21     if(!doing){
22         dp[pos][have]=ans;
23     }
24     return ans;
25 }
26 
27 
28 __int64 solve(__int64 n){
29     int pos=0;
30     while(n){
31         digit[pos++]=n%10;
32         n/=10;
33     }
34     return DFS(pos-1,0,1);
35 }
36 
37 int main(){ 
38     __int64 n,m;
39     memset(dp,-1,sizeof(dp));
40     while(~scanf("%I64d%I64d",&n,&m)){
41         printf("%I64d\n",solve(m)-solve(n-1));
42     }
43     return 0;
44 }
45 
46         

PS:记忆化搜索真的很强大啊。。。

原文地址:https://www.cnblogs.com/wally/p/3006115.html