题目描述,给出一个整数,问你有多少种情况能把这个整数拆分成对称并且是双峰序列的和?
1: (1)
2: (2), (1 1)
3: (3), (1 1 1)
4: (4), (1 2 1), (2 2), (1 1 1 1)
5: (5), (1 3 1), (1 1 1 1 1)
6: (6), (1 4 1), (2 2 2), (1 1 2 1 1), (3 3),
(1 2 2 1), ( 1 1 1 1 1 1)
7: (7), (1 5 1), (2 3 2), (1 1 3 1 1), (1 1 1 1 1 1 1)
8: (8), (1 6 1), (2 4 2), (1 1 4 1 1), (1 2 2 2 1),
(1 1 1 2 1 1 1), ( 4 4), (1 3 3 1), (2 2 2 2),
(1 1 2 2 1 1), (1 1 1 1 1 1 1 1)
很显然要用dp,但是状态转移方程实在难找,忍不住百度了下答案,恍然大悟,dp[i][j]表示和为i的数最小数是j的要求序列的个数
然后dp[i][j]+=dp[i-2*j][k](k=j....i-*j),由于需要递增序列,所以把两端的最小数去掉后,每次求出一种i-2*j的序列,并且最小数
大于j,都可以在此两端分别加上j构成dp[i][j]的一个序列,由此得到这个转移方程
另外此题数据大,需要long long
#include "stdio.h" #define MAXN 250 __int64 opt[MAXN][MAXN]; int n; __int64 ans; int main() { int i,j,k; for (i = 0; i<MAXN; i++) opt[i][0] = opt[i][i] = 1; opt[1][1] = 1; opt[2][1] = 1; opt[2][2] = 1; for (i = 3; i<MAXN; i++) for (j = 1; j<=i/2; j++) { if (i - 2 * j == 0) opt[i][j]++; else for (k = j; k<=i - 2 * j; k++) opt[i][j] += opt[i - 2 * j][k]; } while (scanf("%d",&n) != EOF && n) { ans = 0; for (i = 0; i<=n / 2; i++) ans += opt[n][i]; printf("%d %I64d\n",n,ans); } return 0; }