Integer Partition
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 475 Accepted Submission(s): 218
Following are T lines. Each line contains two numbers, n and k.
1<=n,k,T<=10 5
Since the numbers can be very large, you should output them modulo 10 9+7.
4 4 2 4 3 4 4 4 5
2 4 4 5
题意:把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