概念:所谓整数划分,是指把一个正整数写成几个正整数的和的形式,即 n=∑mi
其中,1≤mi≤n,{m1,m2,...,mk}是n的一个划分。如果max{mi}≤M,则称{m1,m2,...,mk}属于n的一个M划分。
例如:
6 = 6 = 5+1 = 4+2 = 4+1+1 = 3+3 = 3+2+1 = 3+1+1+1 = 2+2+2 = 2+2+1+1 = 2+1+1+1+1 = 1+1+1+1+1+1
所以6一共有11个划分。
解决整数划分问题是基本上都是dp,但对于不同的问题有不同的转移状态,下面将会介绍几类问题。
1.求将n划分成k个正整数之和的划分数
设状态f[n][k]表示n划分成k个正整数之和的方案数,显然,当k>n时,f[n][k]=0, 当k=n时,f[n][k]=1.
下面考虑如何转移
对于k个数中不存在1的情况,我们可以把划分中每个数都减去1,剩下的数仍然大于0,即f[n][k]<----f[n-k][k]
对于k个数中存在1的情况,可以减去这个1,即f[n][k]<-----f[n-1][k-1]
结合两种情况可得转移方程为f[n][k]=f[n-k][k]+f[n-1][k-1]
2.求n的划分数
转移状态及转移方程如1,答案即为∑f[n][i]
3.求n关于m的划分数
这里要求划分出的数不能超过m,考虑以下几种情况
(1) 当n=1时,不论m的值为多少(m>0),只有一种划分即{1};
(2) 当m=1时,不论n的值为多少,只有一种划分即n个1,{1,1,1,...,1};
(3) 当n=m时,根据划分中是否包含n,可以分为两种情况:
(a). 划分中包含n的情况,只有一个即{n};
(b). 划分中不包含n的情况,这时划分中最大的数字也一定比n小,即n的所有(n-1)划分。
因此 f(n,n) =1 + f(n,n-1);
(4) 当n<m时,由于划分中不可能出现负数,因此就相当于f(n,n);
(5) 但n>m时,根据划分中是否包含最大值m,可以分为两种情况:
(a). 划分中包含m的情况,即{m, {x1,x2,...xi}}, 其中{x1,x2,... xi} 的和为n-m,可能再次出现m,是(n-m)的m划分,因此这种划分
个数为f(n-m, m);
(b). 划分中不包含m的情况,则划分中所有值都比m小,即n的(m-1)划分,个数为f(n,m-1);
因此 转移方程为 f(n, m) = f(n-m, m)+f(n,m-1);
4. 求将n划分成若干个奇正整数之和的划分数
设f(n, k) 表示n的划分中最大值为k的划分数。
(1)当 k = 1 时,其结果只能为n个1,当 k 是偶数时,有f(n, k) == f(n, k-1);
(2)当 k > n 时,有f(n, k) = f(n, n),理由同1;
(3)当 n >= k 时,有 f(n, k) = f(n, k-1) + f(n-k, k) <此式中k为奇数,偶数可以对应前面的情况>,前半部分对应n的划分数中最大值不为k,那么可以从k-2开始,式中 k-1 的效果也能达到,同时还能在递推中防止出现下标为负的情况;
5.求n的划分数(n<=50000)
对于如此大的数据范围,需要用到欧拉的五边形定理来加速递推
F(n)表示n的划分数
F(n)=∑{F(n-p(n)/2)+F(n-p(-n)/2)}, 其中p(n)=3n2-n, n<0时F(n)=0, n=0时F(n)=1即可
1 const mo=1000000007; 2 var 3 N,i,j,M :longint; 4 opt :longint; 5 F :array[0..50050] of int64; 6 fi :array[0..50050] of int64; 7 a,b :int64; 8 9 function ff(x:longint):longint; 10 begin 11 exit((3*x*x-x) div 2); 12 end; 13 14 function gg(x:longint):longint; 15 begin 16 exit((3*x*x+x) div 2); 17 end; 18 19 20 begin 21 read(N); 22 M:=trunc(sqrt(N)); 23 F[0]:=1; 24 for i:=1 to N do 25 begin 26 j:=1; 27 while ff(j)<=i do 28 begin 29 if (j and 1=1) then F[i]:=(F[i]+F[i-ff(j)]) mod mo else F[i]:=(F[i]-F[i-ff(j)]+mo) mod mo; 30 inc(j); 31 end; 32 j:=1; 33 while gg(j)<=i do 34 begin 35 if (j and 1=1) then F[i]:=(F[i]+F[i-gg(j)]) mod mo else F[i]:=(F[i]-F[i-gg(j)]+mo) mod mo; 36 inc(j); 37 end; 38 end; 39 writeln(F[N]); 40 end.