您的位置:首页 > 其它

ural1017

2014-09-04 12:36 211 查看

题意

这道题目要求计算给定数目的砖块可以组成多少种不同的楼梯。楼梯由不同高度的阶梯组成,不允许有两个阶梯有相同的高度。每个楼梯至少包含两个阶梯,每个阶梯至少包含一个砖块。

Input

Number N

Output

Number Q

Sample

inputoutput
212995645335
首先来看一下dp的解法,刚开始想的是d
[i]表示n各block 最后一列的长度为i的个数

但是状态转移方程不会。。。。。。囧。。。

后来听了大神的解释只关心最后一列的长度 后面的和前面的没有关系

就像 1 2 5

2 3 5

1 4 5

我们只关心最后一列。但状态转移方程还是不会。。。囧 o(╯□╰)o

但是从这组数中发现了一个问题 ,这个序列是单调递增的,而且和是n.那么我们可以想办法把n拆成多个序列,递增的序列,而且不允许数相等

这就转化成了数的划分问题。查找了资料,真的阔以酱紫做。

参考了一位大神的博客 http://www.cnblogs.com/skyivben/archive/2009/03/02/1401728.html
其实这个讲解的过程也是忽略了很多东西的,因为当人们真的了解了一个问题之后,思维转换的速度非常快,因此懂得的人觉得讲得很清楚了 ,但是听的人还是很不懂。因为懂得人不懂得不懂的人哪里不懂,不懂的人不知道懂的人哪里懂。噗噗噗。。有点像绕口令了。。。跑远了。。首先,我不了解为什么要那么d[k]
表示最小划分元素》=k的个数,可能是因为我没有看原著的原因,这里我就先酱紫忍了。

d[k]
表示最小换分元素的值>=k的划分个数 设最小的是m吧

当m>k时,d[k]
=d[k+1]

当m=k的时候 d[k]
=d[k+1][n-k]就是将所有序列加上k就得到了n-k+k,并且此时的k1>k

d[k]
=0 if(k>n)

d[k]
=1 if(k==n)

d[k]
=d[k+1]
+d[k+1][n-k] else

所以代码就阔以辣,另外有幸的是在上面博客里还有对dp方法的很好的解释。所以用dp的话就是

d
[i]表示n各block有i个台阶(也可以说是有i行)的个数。

首先第一行最少i个,那么第二层i个或者i-1

//还以为可以二项式解决 但好像不能 因为有限制条件 
//  
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
long long d[555][555];//d
[i]表示n方块中最后一行的是 i  .可是状态转移还是不太清楚 
long long v[555];
long long fun(int n,int k) //计算C(n,k) http://jarg.iteye.com/blog/859391 
{
	long long v[505];
	for(int i=0;i<=n;i++)
	{
		v[i]=1;
		for(int j=i-1;j>0;j--)
		 v[i]=v[j]+v[j-1];
	}
	return v[k];
}

int main()
{
	int n,i,j;
	long long res=0;
	scanf("%d",&n);
	  	/*  memset(d,0,sizeof(d));
	    d[1][1]=1;
    	for(i=2;i<=n;i++)
		{
			for(j=1;j*(j+1)/2<=i;j++)
	    	{
	    //	if(j==1 || j==i) d[i][j]=1;
	    	 	d[i][j]=d[i-j][j-1]+d[i-j][j];//这个过程不知道啊。。。。 
	    	}
		}	
	
		for(j=1;j*(j+1)/2<=n;j++)res+=d
[j]; 
	
		cout<<res-1<<endl;//因为加了d[1][1]所以要减去  */
		
	/*正确分析:
	f(n, k)=f(n-k, k)+f(n-k, k-1)
其中n表示砖块的数目,k表示台阶的数目。f(n, k)表示n块砖搭成k阶的方法个数。
那么最下层肯定有k块砖,除去最下层的k块砖,有两种情况,即k-1阶或者k阶。所以可以得到该递推式。
同样可以使用动态规划求解,最终,要求的总方法数为Σf(n, k),其中k=2,…,n。
   */
   
   
    
	/*	memset(v,0,sizeof(v));
		v[2]=1;
		v[3]=3;
		for(i=4;i<=n;i++)
		 v[i]=v[i-1]+i-2;
		 
		 cout<<v
<<endl; //错的 看来找规律要慎重啊。。。 
/*
1 0
2 1
3 3
4 5
5 8
6 12
7 17
8 23
*/
	 
	 
	 //最后一种解法 数的划分  http://www.cnblogs.com/skyivben/archive/2009/03/02/1401728.html 	 //d[k]
表示将n划分的最小元素是k 
	 // =k时 d[][]=d[k][n-k]
	 // >k 时 d[][]=d[k+1]
 
	 memset(d,0,sizeof(d));
	 for(i=1;i<=n;i++)d[i][i]=1;
	 for(i=2;i<=n;i++)
	 {
	 	for(j=i-1;j>=1;j--)
		 d[j][i]=d[j+1][i]+d[j+1][i-j]; 
	 }
	 
	 cout<<d[1]
-1<<endl;
	 
}


经历了种种苦难,觉得dp的状态方程还真是不好推啊。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: