单峰回文脱模

题目描述:
(百度翻译)
如果正整数序列读取相同的前后向,则为回文序列。例如:
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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值