HDU4651 Partition

Partition

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 916    Accepted Submission(s): 527



Problem Description
How many ways can the numbers 1 to 15 be added together to make 15? The technical term for what you are asking is the "number of partition" which is often called P(n). A partition of n is a collection of positive integers (not necessarily distinct) whose sum equals n.

Now, I will give you a number n, and please tell me P(n) mod 1000000007.
 

Input
The first line contains a number T(1 ≤ T ≤ 100), which is the number of the case number. The next T lines, each line contains a number n(1 ≤ n ≤ 10 5) you need to consider.

 

Output
For each n, output P(n) in a single line.
 

Sample Input
  
  
4 5 11 15 19
 

Sample Output
  
  
7 56 176 490

题意:整数拆分,把n分成若干个数相加的种数。

思路:易知其母函数为:G(x)=(1+x+x^2+...)*(1+x^2+x^4+...)*(1+x^n+...),即:


由五边形定理可以知道G(x)=sigma(P(k)x^k),其中P(n)=P(n-1)+P(n-2)-P(n-5)-P(n-7)+...

http://zh.wikipedia.org/wiki/%E4%BA%94%E9%82%8A%E5%BD%A2%E6%95%B8%E5%AE%9A%E7%90%86


#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <string.h>

#define     LL                                 long long
#define     scan(a)                         scanf("%d",&a)
#define     REP(i,a,b)                      for(int i=a;i<b;++i)
#define     mset(a,b)                      memset(a,b,sizeof a)
#define     mod                             1000000007


const int maxn=1e5+10;

using namespace std;

LL ans[maxn];

inline LL pj(LL  j)
{
    LL ret = (3*j*j+j)/2;
    return ret;
}

void init()
{
    mset(ans,0);
    ans[0]=1;
    REP(i,1,maxn)
    {
        for(int j=1;pj(-j)<=i;++j)
        {
            int r=(j%2)?1:-1;
            int a=pj(-j);
            int b=pj(j);
            if(a<=i)
            {
                ans[i]+=ans[i-a]*r;
                ans[i]=(ans[i]%mod+mod)%mod;

            }
            if(b<=i)
            {
                ans[i]+=ans[i-b]*r;
                ans[i]=(ans[i]%mod+mod)%mod;
            }
        }
    }
}

int main()
{
    int t;
    int n;
    init();
    cin>>t;
    while(t--)
    {
        scan(n);
        printf("%I64d\n",ans[n]);
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值