关于整数划分的几类问题

概念:所谓整数划分,是指把一个正整数写成几个正整数的和的形式,即 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.

 

原文地址:https://www.cnblogs.com/zoewilly/p/6708883.html