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;
}    

 

posted @ 2013-05-24 15:14  在于思考  阅读(834)  评论(0编辑  收藏  举报