[动态规划] UNIMODAL PALINDROMIC DECOMPOSITIONS

描述

A sequence of positive integers is Palindromic if it reads the same forward and backward. For example:
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
A Palindromic sequence is Unimodal Palindromic if the values do not decrease up to the middle value and then (since the sequence is palindromic) do not increase from the middle to the end For example, the first example sequence above is NOT Unimodal Palindromic while the second example is.
A Unimodal Palindromic sequence is a Unimodal Palindromic Decomposition of an integer N, if the sum of the integers in the sequence is N. For example, all of the Unimodal Palindromic Decompositions of the first few integers are given below:
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)

Write a program, which computes the number of Unimodal Palindromic Decompositions of an integer.

输入

Input consists of a sequence of positive integers, one per line ending with a 0 (zero) indicating the end.

输出

For each input value except the last, the output is a line containing the input value followed by a space, then the number of Unimodal Palindromic Decompositions of the input value. See the example on the next page.

样例输入

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

解题分析

经典的动态规划题目,也借此引出一个思想,就是动态规划的过程中,如果觉得问题难以描述或者难以用子问题解决,也许是需要更多的信息了,所以不妨多加上几个维度。比如此题,一开始笔者妄图用一维dp数组去解,最后惨败下风。所以后面自己加了一个维度,dp[i][j]代表,对于数字i的UPD分解,两边上的数字为j的时候,分解的数量,并且这个分解是满足中间为最高(对于偶数个情况下中间可以是两个大小一样的数字,比如4分解为(2,2)),然后考虑一个特殊的情况就是数字的自我单独分解,也就是比如4分解为(4),这个我们定义为dp[i][0],好吧,就是单独一个的,我们拎出来说明白。然后,考虑一下我们怎么去更新我们的dp数组,然后,分析一下,我们很容易就明白了,我们旁边的数不可能超过i/2,因为i/2 * 2 = i。dp[i][j]=(dp[i-2*j][0]+dp[i-2*j][1]+...+dp[i-2*j][k]); k=j的情况下,我们可以说dp[i][j]+=dp[i-2*j][0],确保k>=j的情况下,我们用一个循环去累加。

代码实现
#include <iostream>
#include <cmath>
//#include <iomanip>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <list>
#include <bitset>
#include <queue>
#include <stack>
#include <cstdlib>
using namespace std;
int N;
long long dp[255][130]={0};

int main(){
	while(scanf("%d",&N)!=EOF){
		if(N==0) break;
		dp[1][0]=1;
		dp[2][0]=1;
		dp[2][1]=1;
		//dp[i][j]=dp[i-2*j][0]+dp[i-2*j][k];
		for(int i=3;i<=N;i++){
			if(dp[i][0]) continue;
			dp[i][0]=1;
			for(int j=1;j<=i/2;j++){
				if(i-2*j>=j){
					dp[i][j]+=dp[i-2*j][0];
				}
				for(int k=j;k<=(i-2*j)/2;k++){
					dp[i][j]+=dp[i-2*j][k];
				}
				if(i%2==0) dp[i][i/2]=1;
			}
		}
		long long ans=0;
		for(int i=0;i<=N/2;i++){
			ans+=dp[N][i];
		}
		printf("%d %lld\n",N,ans);
	}
	return 0;
}

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值