timus_1013_大整数加法+dp

K进制树,版本3

  题目意思是对于N位的K进制数,其中N位数不包括前导零,求有多少个这样的数满足这N位数中没有相邻的0, 2 ≤ K ≤ 10; N ≥ 2; N + K ≤ 1800。

  输入:N和K

  输出:满足条件的N位数的个数

  样例输入:

  2

  10

  样例输出:

  90

 

思路:

  这道题目可以直接用dp找出状态转移方程。设dp[n]表示n位k进制数中所能满足题目条件的数的个数,那么状态转移方程为:

 

这个方程其实也很直接,由于第n位(最高位)只能取1~k-1的k-1个数,而第n-1位数可以取0~k-1的k个数,dp[n-1]表示的正是第n-1位取1~k-1的k-1个数的情况,而dp[n-2]表示的正是第n-1位取0的情况。

  由于N + K ≤ 1800,所以这很显然需要大整数加法,上面公式中的乘法是可以用加法代替的。

 

源代码:

#include <stdio.h>

#include <string.h>



#define max(a, b) (a > b ? a : b)

int n, k;

int dp[3][2000];



int BigAdd(int *c, int lenc, int *a, int lena, int *b, int lenb)

{

    int i;



    for (i = 0; i < max(lena, lenb); i ++)    

    {

        if (c[i] + a[i] + b[i] > 1000000)

        {

            c[i + 1] += (c[i] + a[i] + b[i]) / 1000000;

            c[i] = (c[i] + a[i] + b[i]) % 1000000;

        }

        else

            c[i] = c[i] + a[i] + b[i];

    }

    while (c[i])

        i ++;

    if (lenc < i)

        lenc = i;

    return lenc;

}



int main ( int argc, char *argv[] )

{

    int i, j;

    int len[3], temp;



    scanf("%d%d", &n, &k);

    dp[1][0] = k - 1;

    len[0] = 1;

    dp[0][0] = 1;

    len[1] = 1;

    for (i = 2; i <= n; i ++)

    {

        memset(dp[i % 3], 0, sizeof(dp[i % 3]));

        len[i % 3] = 0;

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

            len[i % 3] = BigAdd(dp[i % 3], len[i % 3], dp[(i - 1) % 3], len[(i - 1) % 3], dp[(i - 2) % 3], len[(i - 2) % 3]);

    }

    i = len[n % 3] - 1;

    printf("%d", dp[n % 3][i --]);

    for (; i >= 0; i--)

    {

        temp =  dp[n % 3][i];

        j = 0;

        while (temp)

        {

            temp /= 10;

            j ++;

        }

        while (j < 6)

        {

            printf("0");

            j ++;

        }

        printf("%d", dp[n % 3][i]);

    }

    printf("\n");

    return 0;

}    

 

你可能感兴趣的:(dp)