hdu 4658 Integer Partition

Integer Partition

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 475    Accepted Submission(s): 218


Problem Description
Given n, k, calculate the number of different (unordered) partitions of n such that no part is repeated k or more times.
 

Input
First line, number of test cases, T.
Following are T lines. Each line contains two numbers, n and k.

1<=n,k,T<=10 5
 

Output
T lines, each line contains answer to the responding test case.
Since the numbers can be very large, you should output them modulo 10 9+7.
 

Sample Input
  
  
4 4 2 4 3 4 4 4 5
 

Sample Output
  
  
2 4 4 5
 

Source
 

Recommend
zhuyuanchen520   |   We have carefully selected several similar problems for you:   5227  5226  5225  5224  5223



题意:把n分拆成若干个整数相加,最多不超过k-1个重复的数,

思路:用母函数的方法。

    生成函数(也有叫做“母函数”的)是说,构造这么一个多项式函数g(x),使得x的n次方系数为f(n)。
这题用到的1+x+x^2+...,f[n]就是全由1组成的n有多少种,显然是1.类似的1+x^2+x^4+..表示的就是全部由2组成,
两者相乘的意义就在于(1+x+x^2)*(1+x^2)=1+x+2*x^2+x^3+x^4,其中x^2系数2表示拆分整数2的方案数,2=1+1=2,共2种


    所以无限制的拆分就可以理解成(1+x+x^2+x^3+...)*(1+x^2+x^4+..)*..*(1+x^k+x^2k+...)*..中x^n的系数就是所求值
    这题加了k的限制,所以得到的生成函数式:
    (1+x+x^2+...+x^(k-1))*(1+x^2+x^4+x^2(k-1))*...(每个括号内斗是等比数列求和)
    =(1-x^k)/(1-x)*(1-x^2k)/(1-x^2)*(1-x^3k)/(1-x^3)...(令y=x^k)
    =∏(1-y^i)/∏(1-x^i)(1<=i<∞)=g[y]/g[x]
∏(1-x^i)形式的可用五边形数定理来求,详细的请百度和谷歌
五边形定理:


再由可知

1/g[x]的系数

p[n]=∑(-1)^(k-1)*(p[n-k*(3*k-1)/2]+p[n-k*(3*k+1)/2]),dp一下就能出来了

之后答案就是求(1-x^k-x^2k+x^5k+x^7k-x^12k-x^15k+x^22k+x^26k)*(1+p(1)x+p(2)x+p(3)x+...)中x^n的系数了

前者用五边形数定理求出指数x和系数flag,找到∑p[n-x]*flag就是结果了




#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;
            }
        }
    }
}

LL solve(int n,int k)
{
    LL ret=ans[n];
    for(int i=1;pj(-i)*k<=n;++i)
    {
        int r=(i%2)?-1:1;
        LL a=pj(-i)*k;
        LL b=pj(i)*k;
        if(a<=n)
        {
            ret += ans[n-a]*r;
            ret =(ret%mod+mod)%mod;
        }
        if(b<=n)
        {
            ret += ans[n-b]*r;
            ret=(ret%mod+mod)%mod;
        }
    }
    return ret;;
}

int main()
{
    int t;
    int n,k;
    init();
    cin>>t;
    while(t--)
    {
        scan(n);
        scan(k);
        int pr=(int)solve(n,k);
        printf("%d\n",pr);
    }
}






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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值