【hdu 4658】Integer Partition (无序分拆数、五边形数定理)

hdu 4658 Integer Partition

题意

n分拆成若干个正整数的和,每个正整数出现小于k次,分拆方案有多少。(t<=100,n<=1e5)

题解

之前写过一篇Partition Numbers的计算,后面补充了hdu 4651的做法。就是利用五边形数定理。
这题加强了限制条件。

n的无序分拆数的生成函数:
\(\sum_{i=1}^{\infty}B(i)x^i=(1+x+x^2+..)(1+x^2+x^4+..)…=\frac {1}{\prod_{i=1}^{\infty}(1-x^i)}\)

由五边形数定理知

\(\prod_{n=1}^{\infty}(1-x^n)=\sum_{k=0}^\infty (-1)^k x^{\frac {k(3k\pm 1)}{2}}\)

\((1+B(1)x+B(2)x^2+..)(1-x-x^2+x^5+x^7+..)=1\)

比较两边\(x^n\)系数,得到

\(B(n)-B(n-1)-B(n-2)+B(n-5)+B(n-7)+..=0\)

所以可以\(O(n^{1.5})\)计算出B。

有了限制,生成函数变成
\(g(x)=(1+x+x^2+..+x^{k-1})(1+x^2+x^4+..+x^{2(k-1)})…= {\prod_{i=1}^\infty(1-x^{ik})}B(x)\)

再利用五边形数定理得

\(g(x)=(1-x^k-x^{2k}+x^{5k}+..)(1+B(1)x+B(2)x^2+B(3)x^3+..)\)

\(x^n\)的系数即为答案。

代码

int n,k;
int B[N]={1,1,2};
int main() {
	int t;
	sf(t);
	for(int i=3;i<N;++i)
	for(int j=1,f=1;f;++j)
	for(int k=-1;k<2;k+=2){
		int w=(3*j*j+k*j)/2;
		if(w>i){f=0;break;}
		if(j%2)B[i]=(B[i]+B[i-w])%mod;
		else B[i]=(B[i]-B[i-w]+mod)%mod;
	}
	while(t--){
		sf(n);sf(k);
		int ans=0;
		ans=B[n]%mod;
		for(int i=1,f=1;f;++i)
		for(int j=-1;j<2&&f;j+=2){
			int w=(3*i*i+j*i)/2;
			if(w*k>n){f=0;break;}
			if(i%2==0)ans=(ans+B[n-w*k])%mod;
			else ans=(ans-B[n-w*k]+mod)%mod;
		}
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2017-09-04 20:30  水郁  阅读(744)  评论(0编辑  收藏  举报
……