HUST1380:NumberPyramids

NumberPyramids

Time Limit: 20 Sec   Memory Limit: 128 MB
Submissions: 103   Solved: 41

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.
baseLength
will 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





非常V5的一道题,一开是以为但是DP,1,000,000的数据范围真的有点不能接受......
看了一个大牛的题解,用数论证明了这个题可以转化成多重背包.....

思路:
首先,我们可以证明金字塔最顶端的数和最低端的数是有关系的,关系就是
C0N-1*a0 +  C 1 N-1* a 1 + C 2 n-1 * a 2 + ......  C n-1 n-1 * a n-1  = T       (1)

而且因为T <= 1,000,000。可以推出n最大是20.....
继续观察上述(1),因为必须符合金字塔,所以a序列都至少为1,所以,我们可以发现,先用T减去每个系数(因为至少一次),之后用那n-1个数做多重背包,求T的方案就行了。

复杂度是(N * 1,000,000),可以接受。

代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using  namespace std;

const  int mod = 1000000009;
int dp[1000100];
int n, top;
int c[21][21];
void init()
{
     for ( int i = 1; i < 21; ++i)
    {
        c[i][0] = c[i][i]  = 1;
        c[i][1] = c[i][i - 1] = i;
         for ( int j = 2; j < i - 1; ++j)
        {
            c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
        }
    }
}

int work( int n,  int top)
{
     if (n > 20)  return 0;
     if (1 << (n - 1) > top)  return 0;
    top -= 1 << (n - 1);
    memset(dp, 0,  sizeof(dp));
    dp[0] = 1;
     for ( int i = 0; i <= n - 1; ++i)
    {
         for ( int k = 0; k <= top; ++k)
        {
             if ((dp[k] && k + c[n - 1][i] <= top) || k == 0)
            {
                dp[k + c[n - 1][i]] = (dp[k + c[n - 1][i]] + dp[k]) % mod;
            }
        }
    }
     return dp[top];
}

int main()
{
    memset(c, -1,  sizeof(c));
    init();
     while (scanf("%d%d", &n, &top) != EOF)
    {
        printf("%d\n", work(n ,top));
    }
     return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值