数位DP总结

数位DP=区间求符合条件的数的个数的算法=数很大,无法直接暴力的算法≈让人苦恼愤怒,依然D不出来的勾魂算法

数位DP的两种写法:

1、递推

 结构:

init()函数,根据递推数位的公式求得的满足某长度的符合数的个数

cal()函数,假设要计算的数字为n,数位长度为len。1到len-1长度累加,len长度的拿出来一个位置一个位置遍历判定再累加。

输出cal(right+1)-cal(left),right为区间最右,left为区间最左

 

模板:

int f[35][35],digit[35];

void Init()

{

    int i,j;

    /*递推关系式,请忽略

    f[0][0]=1;

    for(i=1; i<32; ++i)

    {

        f[i][0]=f[i-1][0];

        for(j=1; j<=i; ++j)

            f[i][j]=f[i-1][j]+f[i-1][j-1]; 

    }

    */

}



int Cal(int x,int k,int b) 

{

    int tot=0,len=0,ans=0,i;

    while(x) //初始化数位

    {

        digit[++len]=x%b;

        x/=b;

    }

    for(i=len;i&&tot<=k;--i) //分长度累加

    {

      /*判断累加,请忽略

      if(digit[i]>1)  

      {

          ans+=f[i][k-tot];break;

      }

      if(digit[i]==1) 

      {

          ans+=f[i-1][k-tot];

          tot++;

      }

      */

    }

    return ans;

}

输出Cal(right+1)-Cal(left)

 

2、递归(记忆化搜索,据说记忆化搜索最优)

个人觉得记忆化搜索更简单,因为它的结构简单。dp数组d的是pos前面数组的状态。

结构:

dfs()函数,记忆化搜索符合条件的数的个数。记忆化搜索的参数无非是表示上一状态或者是下一状态的。

cal()函数,初始化数位,调用dfs函数。

输出cal(right)-cal(left-1)

 

模板:

int dfs(int pos , int pre , int have , bool doing) //doing为边界,pos为计算到当前第几位

{

    if(pos == -1)

        return have == 2 && pre == 0;



    if(!doing && dp[pos][pre][have] != -1) //若不是统计边界位,则直接返回记忆下的数

        return dp[pos][pre][have];



    int ans = 0;

    int end = doing ? digit[pos] : 9; 

    for(int i = 0 ; i <= end ; i ++)

    {

       /*初始化下一层dfs的参数,请忽略 

        int npre = (pre*10 + i) % 13; 

        int nhave = have;

        if(have == 0 && i == 1)

            nhave = 1;

        else if(have == 1 && i != 1)

            nhave = 0;

        if(have == 1 && i == 3)

            nhave = 2;

        */

        ans += dfs(pos-1 , npre , nhave , doing && i == end ); //doing在i==end的时候会是1

    }



    if(!doing)

        dp[pos][pre][have] = ans;

    return ans;

}





int cal(int x)

{

    int pos = 0;

    while(x)

    {

        digit[pos++] = x % 10;

        x /= 10;

    }

    return dfs(pos - 1 , 0 , 0 , 1);

}
输出Cal(right)-Cal(left-1)

 

你可能感兴趣的:(总结)