hdu 3652 -数位dp

之前学校新生培训的时候学长挂的题,当时给了标准代码没看明白,放了半年,今天花一天总算看明白了,从这个过程也能看出这半年学习是有不少进步的,代码的理解有一定的加深,不过单看数位dp7k+那个缩减模版有的地方确实是有点丧心病狂了,所以参照了另一个注释写的比较多的博主http://blog.csdn.net/xingyeyongheng/article/details/8806414最后思路综合了下,写了一个符合自己感觉的写法,明天找机会继续练练数位dp。

#include
#include

const int max=10+5;

//由基础模版dp[max][3]衍变,max代表的是数的最大长度会是多少,3代表的三种状态; 
//这里由于还有一个要求是除了数要包含13以外还需要被13整除,那么就需要再增加一维来代表余数 
/*
假设pos为输入数的转化为对应数位后的最大下标:
  dp[i][j][0]表示从pos到i+1位不含有13且接下去长度<=i的模13为j的数的个数 
  dp[i][j][1]表示从pos到i+1位不含有13但是第i+1位是1且接下去长度<=i的模13为j的数的个数 
  dp[i][j][2]表示从pos到i+1位含有13且接下去长度<=i的模13为j的数的个数  
*/
                         
int dp[max][3][13]; 
int digit[max];//储存每一位的数 

//pos代表处理到的位置,s为状态,mod为当前总的余数,flag作为一个标记比如输入数为123 
//处理到3,如果前面我们取得'2'的那位要的是2 那么我们flag=0
int dfs(int pos,int s, int mod,int flag){//表示后面不可以直接从129开始遍历,反之如果小于2,那么就可以从119开始遍历
    if(pos==-1)return s==2&&mod==0;//如果所有位都考虑完了,就判断返回必须是状态2且总余数为0才符合要求                                    
    if(flag&&dp[pos][s][mod]!=-1)return dp[pos][s][mod];//表示pos后面的位数可以是从9-1的任意数了在有值得情况下可以直接返回 
    int sum=0;
    int size = flag?9:digit[pos];//当前数可不可以从9开始,得看flag标记的前一位数是不是取了它最大的情况 
    for(int i=0;i<=size;i++){
        int t;//记录状态转移 
        if(s==2)t=2;//原来就已经包含13 
        else{
             if(s==1&&i==3)t=2;//原来有1,现在有3那么刚好存在13
             else if(i==1)t=1;
             else t=0;
        }
        int MOD=(mod*10+i)%13;//传到下一位总余数也要传递一下
        sum+=dfs(pos-1,t,MOD,flag||i


你可能感兴趣的:(dp,hdu,数位dp)