HUST1380NumberPyramids题解动态规划

探讨了如何计算特定条件下数字金字塔的数量,通过将问题转化为求解特定线性方程组的正整数解数目,并使用动态规划的方法高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

NumberPyramids

Time Limit: 20 Sec  Memory Limit: 128 MB
Submissions: 91  Solved: 33

Description

 

Suppose that there are N numbers written in a row. A row above this one consists of N-1 numbers, the i-th of which is the sum of the i-th and (i+1)-th elements of the first row. Every next row contains one number less than the previous one and every element is the sum of the two corresponding elements in the row below. The N-th row contains a single number. For example, if the initial numbers are {2,1,2,4}, the whole structure will look like this:

15
6 9
3 3 6
2 1 2 4

We shall refer to such a structure as a number pyramid. Two number pyramids are equal if all the numbers at corresponding positions are equal. Given ints baseLength and top, compute the total number of different number pyramids consisting of positive integers, having baseLength elements in the first row and the value at the top equal to top. Since the number of such pyramids might be enormous, return the result modulo 1,000,000,009.

 

Input

 

Two numbers -- baseLength and top.
baseLengthwill be between 2 and 1,000,000, inclusive.
topwill be between 1 and 1,000,000, inclusive.

 

Output

 

The total number of different number pyramids Constraints

 

Sample Input

3 5
5 16
4 15
15 31556
150 500

Sample Output

2
1
24
74280915
0

HINT

 

1) The following are two possible pyramids with 3 numbers in the base and the number 5 at the top:

2) The only number pyramid with base of size 5 and 16 at the top looks like this:

 

Source

Topcoder SRM

 

 

NumberPyramids  
Used as: Division One - Level Two:

Value 500
Submission Rate 209 / 653 (32.01%)
Success Rate 161 / 209 (77.03%)
High Score Petr for 475.02 points (6 mins 34 secs)
Average Score 289.10 (for 161 correct submissions)

The first important observation we make is that every unique pyramid corresponds to a unique base row. This follows from the following reasons:-

  • If we know every element in the base row, then the rest of the pyramid is uniquely determined since we can compute the entire pyramid from bottom to top. Hence, equal base rows => equal pyramids.
  • Moreover, if the base rows are unequal (i.e. there is atleast one unequal element), then clearly the pyramids are unequal. [Since we have atleast one pair of unequal elements]

Therefore, finding the number of different pyramids corresponds to finding the number of distinct base rows of length baseLength so that the top element is top.

Now, we deduce the relation between the top element and the elements in the base row.
Let us denote the jth element (0-based) of row i (row 0 being the topmost row) by xij, i.e. x00 = top element.
x00
= x10 + x11
= (x20 + x21) + (x21 + x22)
= x20 + 2*x21 + x22
= (x30 + x31) + 2*(x31 + x32) + (x32 + x33)
= x30 + 3*x31 + 3*x32 + x33
Hey! The coefficients are the same as binomial coeffients. And they must be, since the coefficeints are being computed in the exact same way as the pascals triangle is calculated.

So we have, top = C(r,0)*xr0 + C(r,1)*xr1 + C(r,2)*xr2 + ... + C(r,r)*xrr
where r can be any row, and C(n, m) denotes the number of ways of selecting m elements from a set of n elements.
For our problem, we have r = baseLength-1, and xri ≥ 1.

If we define yi as (xri-1), then we have
top - (∑(C(r,i)) where 0 ≤ i ≤ r) = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... + C(r,r)*yr
or, top - 2r = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... + C(r,r)*yr
and, each yi ≥ 0
The number of distinct base rows is equal to the number of distinct solutions we have for the above equation.

Now, let us define DP[i][j] as 'number of distinct solutions of j = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... + C(r,i)*yi (where each yk≥0)'
(We need to return DP[r][top - 2r]).

We find a way to compute DP[i][j] = (number of distinct solutions of j = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... + C(r,i)*yi (where each yk≥0))
Two cases may arise, yi = 0 and yi ≥ 1
Case 1: yi = 0
(number of distinct solutions of j = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... C(r,i-1)*yi-1 + C(r,i)*yi where yi = 0 )
is simply, (number of distinct solutions of j = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... + C(r,i-1)*yi-1)
= DP[i-1][j]
Case 2: yi ≥ 1
(number of distinct solutions of j = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... C(r,i-1)*yi-1 + C(r,i)*yi where yi≥1)
= (number of distinct solutions of j = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... C(r,i-1)*yi-1 + C(r,i)*(yi+1) where (yi+1)≥1) ...      [Replacing yi by (yi+1) throughout]
= (number of distinct solutions of j-C(r,i) = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... C(r,i-1)*yi-1 + C(r,i)*yi where yi≥0) ...         [Transposing one C(r,i) from RHS to LHS & using (yi+1)≥1 implies yi≥0]
= DP[i][j-C(r,i)]

Since the two cases are mutually exclusive and exhaustive, we have (total number of solutions) = sum of (number of solutions) for each of the individual cases. Hence, we get
DP[i][j] = DP[i-1][j] + DP[i][j-C(r,i)]

One last observation will make our code even simpler. Notice that if we use the final recurrence to compute the values of DP in row-major order, then we never access an element more than width behind, where width is the number or columns in DP. Hence, at any point of time we need to store only the last width elements. This makes it possible for us to use a 1D array, even though the explanation given above is 2D. It does not save us time, it just saves us memory (and labor).

Note that we need to use MOD when we are actually computing the values in the array DP. And also that we must return 0 if (top - 2r) is negative.

Here is an implementation of the above:-

int count(int baseLength, int top) 
{ 
	int C[21], r = baseLength-1, DP[1000001]; 
	if (r >= 20) return 0; 
	top -= (1<<r); if (top < 0) return 0; 
	// Compute the binomial coeffients 
	memset(C, 0, sizeof(C)); C[0] = 1; 
	for (int i = 1; i <= r; i++)
		for (int j = i; j > 0; j--)
			C[j] += C[j-1]; 
	// Compute DP[i][j] in 1D fashion
	memset(DP, 0, sizeof(DP)); DP[0] = 1; 
	for (int i = 0; i <= r; i++)
		for (int j = C[i]; j <= top; j++)
			DP[j] = (DP[j]+DP[j-C[i]])%MOD;
	return DP[top];
}


The problem of finding the number of distinct solutions of B = A0*x0 + A1*x1 + A2*x2 + ... An*xn, where each Ai and B is known to you, is a pretty standard problem. You should expect to encounter it time and again in coding competitions.

 

 

题意为:

15
6 9
3 3 6
 2 1 2 4

如上所示的数字金字塔,最底层有baseLength<=1,000,000个正整数,数的个数按层递减,每个数都是下方两个数的和,问最底层baseLength个数而最上面的数为top<=1,000,000的数字金字塔方案有多少个。

分析:

首先显然可以知道的是当最底层被确定的话就可以确定一个数字金字塔,也就是每个数字金字塔可以用他的最底层来唯一确定。

那么,求数字金字塔的个数就可以转换为求最底层的baseLength个数的不同组合个数。

现在我们要找的就是顶端元素与底层所有元素之间的关系,令xij表示第i行(从0开始)的第j个数(从0开始),则顶端元素top = x00,那么我们可以推出:

x00
= x10 + x11
= (x20 + x21) + (x21 + x22)
= x20 + 2*x21 + x22
= (x30 + x31) + 2*(x31 + x32) + (x32 + x33)
= x30 + 3*x31 + 3*x32 + x33

观察可发现每项前的系数正是二项式系数,所以我们可以得到:

top = C(r,0)*xr0 + C(r,1)*xr1 + C(r,2)*xr2 + ... + C(r,r)*xrr,其中r可以是(0..baseLength-1)之间的任意行,且有xri ≥ 1,从这里可推出baseLength至多为20。

那么题意转化为:B = A0*x0 + A1*x1 + A2*x2 + ... An*xn,Ai和B已知,求不同解(xi>=1)的个数。

令yi = (xri-1),那么有:

top - (∑(C(r,i)),0 ≤ i ≤ r) = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... + C(r,r)*yr
top - 2r = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... + C(r,r)*yr,且(yi ≥ 0)。

那么可以将上式抽象为背包,容量top - 2^r,有r个物品每个物品的容量为C(r,i),问使背包放满的方案个数。

显然我们可以令dp[i][j]表示前i个物品放了j容量时的方案个数,即使j = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... + C(r,i)*yi,且yk≥0,那么答案就是dp[r][top - 2r]。

则对于第i个物品,我们有如下决策:

yi=0,那么 j = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... C(r,i-1)*yi-1 + C(r,i)*yi = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... + C(r,i-1)*yi-1),所以dp[i][j]方案数=dp[i-1][j]。
yi>=1,那么j = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... C(r,i-1)*yi-1 + C(r,i)*yi,且yi≥1,令yi+1 = yi,那么j = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... C(r,i-1)*yi-1 + C(r,i)*(yi+1),且yi≥0,即等价于j-C(r,i) = C(r,0)*y0 + C(r,1)*y1 + C(r,2)*y2 + ... C(r,i-1)*yi-1 + C(r,i)*yi,且yi≥0,所以dp[i][j]方案数=dp[i][j-C(r,i)]。

综上有dp[i][j] = dp[i-1][j] + dp[i][j-C(r,i)],又因为dp[i][j]第一维按行枚举的话可以省略,故空间可降至一维。

这样我们就可以得到经典的背包方程dp[j] = dp[j] + dp[j-C(r,i)],再处理一下取模MOD即可完美解决。

 

代码:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值