题目描述:
(百度翻译)
如果正整数序列读取相同的前后向,则为回文序列。例如:
23 11 15 1 37 37 1 15 11 23
1 1 2 3 4 7 7 10 7 7 4 3 2 1 1
如果值不降低到中间值,则回文序列是单峰回文序列,然后(由于该序列是回文序列)不从中间增加到终点,例如,上面的第一个示例序列不是单峰回文序列,而第二个例子是。
单峰回文序列是整数N的单峰回文分解,如果数列中的整数之和为N,例如,前几个整数的单峰回文分解如下:
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)
编写一个程序,计算一个整数的单峰数。
输入
输入由一系列正整数组成,一行以0(0)结尾,表示结束。
输出
对于除最后一个输入值以外的每个输入值,输出是一个包含输入值的行,后面是一个空格,然后是输入值的单峰Palindrom分解数。参见下一页中的示例。
样例输入
2
3
4
5
6
7
8
10
23
24
131
213
92
0
样例输出
2 2
3 2
4 4
5 3
6 7
7 5
8 11
10 17
23 104
24 199
131 5010688
213 1055852590
92 331143
提示
n<250
AC代码如下:
/*
奇数 n 只可能有长度为奇数的单峰回文划分;
而偶数则可以有长度为奇数的回文划分,也可以有长度为偶数的回文划分。
*/
#include<iostream>
#include<algorithm>
using namespace std;
long long dp[300][300] = {0};//表示左边元素之和为i,元素不大于j的情况个数总数
int main()
{
int n;
for(int i = 0; i < 300; i++)//初始化
{
dp[0][i] = 1;
}
for(int i = 1; i < 300; i++)
{
for(int j = 1; j < 300; j++)
{
if(j < i)
{
dp[j][i] = dp[j][i - 1];//方程
continue;
}
dp[j][i] = dp[j][i - 1] + dp[j - i][i];//状态转移方程
/**
* 划分中每个数都小于 m, 相当于每个数不大于 m- 1, 故划分数为 dp[n][m-1]。
* 划分中有一个数为 m. 那就在 n中减去 m , 剩下的就相当于把 n-m 进行划分, 故划分数为 dp[n-m][m];
**/
}
}
while(1)
{
cin >> n;
if(n == 0) break;
long long sum = 0;
if(n % 2 != 0)//奇数情况
{
int s;
for(int v = 1; v < n; v++)//先定下来中间的那个数,剩下的放两边
{
if((n - v) % 2 == 0)//做左右对称的情况,数字个数是奇数
{
s = (n - v) / 2;
sum += dp[s][v];//一边按照总和是s,不超过v的情况取
}
}
}
else//是偶数
{
int s;
//有两种情况,形成的数列是奇和偶数列
for(int v = 1; v < n; v++)//取定奇数列中间的那个数
{
if((n - v) % 2 == 0)
{
s = (n - v) / 2;
sum += dp[s][v];//一边按照总和是s,不超过v的情况取
}
}
s = n / 2;//偶数数列
sum += dp[s][s];
}
sum++;//本身
cout << n << " " << sum << endl;
}
system("pause");
return 0;
}