码迷,mamicode.com
首页 > 其他好文 > 详细

dp1221

时间:2014-08-13 18:12:06      阅读:243      评论:0      收藏:0      [点我收藏+]

标签:style   blog   color   os   io   for   ar   问题   

类似于整数分解,但要求分解得到的式子是回文,且前半部分单调非递减,后半部分单调非递增

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)

 

首先要说明的是此题结果会很大。开始用的long long 提交后WA ,后来换成__int64过了。

而第二个问题就是重点了。令 f(n,m) 表示 的划分 P = {n1, n2, ..., nk | k>= 1, 0 < ni  <= m  for 1<=i <= k, n1+n2+...+nk = n} 的个数,M表示所有的构成因子都必须小于等于M则我们有递归方程式 

        1) m == 1,则 f(n,m) = 1,也就是只有 {1, 1, ... 1 } 这种划分;

        2) m==n,则 f(n,m) = f(n, m-1) + 1,也就是除了划分 {n},在其它的划分中,元素都小于或等于 m-1

        3) 否则,f(n,m) = f(n,m-1) + f(n-m, min(n-m,m))。分为最大不超过m-1的情况加上因数有一个为m的情况(后一种情况里,可能有一个M或者两个,但肯定有一个,有可能不是两个同时存在;另外后一个情况里,存在一个M后,所有因子必须小于M,这是显然,但还必须小于N-M)

也就是把n分为因数最大不超过m的分法有多少种。这就是此题的核心。把这个弄清楚了之后我是分两种情况讨论的。即奇数和偶数。不论奇数还是偶数都是看中间的数。两边的数列是以中间的数中心对称的且都小于中间的数这里的DP都是仅仅考虑最中间数的一边的情况,并不是两边同时考虑。仅仅考虑一边的数从大到小排列的情况数

 

dp[i][j] = dp[i][j-1] + dp[i-j][min(i-j,j)];这个公式本身就考虑到了序列顺序的问题(必须上升再下降)

比如dp[8][6]=dp85+dp22,dp85=dp84+dp33,dp84=dp83+dp44,dp83=dp82+dp53,可见 f(n,m-1)其实是逐渐下降的,而dp[i-j][min(i-j,j)],其实是表示中间的元素首选取J,(可能有一个,对于奇数情况;可能是两个,偶数情况),比如dp82=dp81+dp62,dp62=dp61+dp42,dp42=dp41+dp22.也就是说dp[i-j][min(i-j,j)]是从大到小递减的,dp62表示8里面已经取了2(最大值,在中间,看做xxx2xxx),dp42表示和为6的序列中间取最大值2(此时序列为xx22xx),dp22表示和为2的序列再取最大值2,此刻dp22表示序列为xxx222xxx形式,能加的元素最大不超过2,和为2,共有两种可能12221,2222

  总结一下,即dp[i][j] = dp[i][j-1] + dp[i-j][min(i-j,j)];前半部分是通过j-1逐渐减一,得到全为1的可能,它的意思在于最大值不超过j-1.后半部分表示必须存在最大值j,且把它放在中间位置(当然可能取值为0

 

#include <iostream>#include <algorithm>#include <cmath>
using namespace std;__int64 dp[301][301];
int main() {    
int a;    
for (int i = 1;i <= 300;i++)
{        
    dp[i][0] = 0;
    dp[0][i] = 0;        
    dp[i][1] = 1;        
    for (int j = 1;j <= 300;j++) 
    {            
        if(i == j) 
        dp[i][j] = dp[i][j-1] + 1;            
        else if(i < j) 
        dp[i][j] = dp[i][i];            
        else
        dp[i][j] = dp[i][j-1] + dp[i-j][min(i-j,j)];        
    }    
}      

while(cin >> a && a)
{       
    __int64 s = 1;//只有一个构成元素A的情况 必须单独考虑因为下面的公式a-i=0时,返回0        
    if(a%2) 
    //奇数的时候            
    for(int i = 1;i < a;i+=2)
{    //奇数必定存在于中间的各个情况,如果中间奇数为i则所有值必须小于i                
    s += dp[(a-i)/2][i];//i表示最中间的数大小        
    else 
    {            
        s += dp[a/2][a/2];//中间偶数为0,则两边的数列和都为a/2,极限情况为(a/2 |a/2)
        for(int i = 2;i < a;i+=2) //偶数存在于中间的各个情况                
        s += dp[(a-i)/2][i];        
    }        
    cout <<a<<" "<<s <<endl;    
}    
return 0;
}

 

 

 

dp1221,布布扣,bubuko.com

dp1221

标签:style   blog   color   os   io   for   ar   问题   

原文地址:http://www.cnblogs.com/notlate/p/3910353.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!