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:记忆化搜索真的很强大啊。。。

你可能感兴趣的:(HDU)