zoukankan      html  css  js  c++  java
  • 关于整数划分的几类问题

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

     

  • 相关阅读:
    我的第一篇博客
    1.2 位于Shell脚本第一行的#!
    1.1 一个简单的脚本
    JDK与CGlib动态代理的实现
    解决Sublime Text3中文显示乱码问题
    多线程讲解
    (转)Spring中@Async用法总结
    (转)spring boot注解 --@EnableAsync 异步调用
    Spring Boot中的注解
    (转)如何用Maven创建web项目(具体步骤)
  • 原文地址:https://www.cnblogs.com/zoewilly/p/6708883.html
Copyright © 2011-2022 走看看