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