zoukankan      html  css  js  c++  java
  • hdu 1028

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    生成函数是说,构造这么一个多项式函数g(x),使得x的n次方系数为f(n)。

    对于母函数,看到最多的是这样两句话:

    1.“把组合问题的加法法则和幂级数的乘幂对应起来。”

    2.“把离散数列和幂级数一 一对应起来,把离散数列间的相互结合关系对应成为幂级数间的运算关系,最后由幂级数形式来确定离散数列的构造。 “

    例子:

    有1克、2克、3克、4克砝码各一枚,问能称出哪几种重量?每种重量各有几种方案?

    下面是用母函数解决这个问题的思路:

    首先,我们用X表示砝码,X的指数表示砝码的重量。那么,如果用函数表示每个砝码可以称的重量,

    1个1克的砝码可以用函数X^0 + X^1表示,

    1个2克的砝码可以用函数X^0 + X^2表示,

    依次类推。

    如果我们把上面2个多项式相乘,可以得到X^0 + X^1 + X^2 + X^3。继续把它与X^0 + X^3相乘,得到X^0 + X^1 + X^2 + 2*X^3 + X^4 + X^5 + X^6。

    接着把它与X^0+X^4相乘,最后得到X^0 + X^1 + X^2 + 2*X^3 + 2*X^4 + 2*X^5 + 2*X^6 + 2*X^7 + X^8 + X^9 + X^10。

    由于X的指数表示的是重量,所以,在相乘时,根据幂的运算法则(同底幂相乘,指数相加),得到的结果正是所有的方案。而且,每个X前面的系数代表它有几种方案。

    需要注意的是,如果有2个1克的砝码,应该用X^0 + X^1 + X^2表示,而不是X^0 + 2*X^1。

    母函数还可以解决其他问题,比如,整数划分。

    整数划分是个很经典的问题,划分规则就不再细述,直接说思路。与上面的问题相比,每种砝码的个数不再是1个,而是无限个。于是,

    1克的砝码可以用X^0 + X^1 + X^2 + X^3 ……表示,

    2克的砝码可以用X^0 + X^2 + X^4 + X^6……表示,

    3克的砝码可以用X^0 + X^3 + X^6 + X^9……表示,

    依次类推。

    相乘后求出X^n的系数,就是结果。

    总而言之,解决此类问题,只要模拟好2个多项式相乘就好了。

    大概思路是开2个数组,c1[ ]保存当前得到的多项式各项系数,c2[ ]保存每次计算时的临时结果,当每次计算完毕后,把它赋给c1,然后c2清零。

    计算的时候,开3层for循环。最外层,记录它正在与第几个多项式相乘。第二层,表示c1中的每一项,第三层表示后面被乘多项式中的每一项。

    hdu 1028 整数分解:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int lmax=40007;
    int c1[lmax],c2[lmax];
    //G(x)=(1+x+x^2+x^3+...)*(1+x^2+x^4+...)*(1+x^3+x^6+...)+..
    int main()
    {
        int n;
        while(cin>>n)
        {
            for(int i=0;i<=n;i++)
            {
                c1[i]=1;//用来保存当前得到的多项式的各项系数
                c2[i]=0;//用来保存每次计算时的临时结果
            }
            for(int i=2;i<=n;i++)//记录c1正在与第几个多项式进行运算
            {
                for(int j=0;j<=n;j++)//c1中的每一项前的系数
                {
                    for(int k=0;k+j<=n;k+=i)//表示被乘多项式的每一项的系数
                    {
                        c2[k+j]+=c1[j];//每计算一次并把它赋给用于临时保存数据的c2
                    }
                }
                for(int j=0;j<=n;j++)
                {
                    c1[j]=c2[j];//每次计算完毕后,就把它赋给c1
                    c2[j]=0;//然后c2清零
                }
            }
            cout<<c1[n]<<endl;
        }
    }
    

    以下是不同情况下的变化了:

    http://acm.hdu.edu.cn/showproblem.php?pid=1085

    直接贴代码了:

     1  #include <iostream>
     2 using namespace std;
     3  
     4 int c1[10000], c2[10000];
     5 int num[4];
     6 int main()
     7 {
     8     int nNum;
     9     while(scanf("%d %d %d", &num[1], &num[2], &num[3]) && (num[1]||num[2]||num[3]))
    10     {
    11         int _max = num[1]*1+num[2]*2+num[3]*5;
    12         // 初始化
    13         for(int i=0; i<=_max; ++i)
    14         {
    15             c1[i] = 0;
    16             c2[i] = 0;
    17         }
    18         for(int i=0; i<=num[1]; ++i)     
    19             c1[i] = 1;
    20         for(int i=0; i<=num[1]; ++i)
    21             for(int j=0; j<=num[2]*2; j+=2) 
    22                 c2[j+i] += c1[i];
    23         for(int i=0; i<=num[2]*2+num[1]*1; ++i)   
    24         {
    25             c1[i] = c2[i];
    26             c2[i] = 0;
    27         }
    28  
    29         for(int i=0; i<=num[1]*1+num[2]*2; ++i)
    30             for(int j=0; j<=num[3]*5; j+=5)
    31                 c2[j+i] += c1[i];
    32         for(int i=0; i<=num[2]*2+num[1]*1+num[3]*5; ++i)    //看到变化了吗
    33         {
    34             c1[i] = c2[i];
    35             c2[i] = 0;
    36         }
    37         int i;
    38  
    39         for(i=0; i<=_max; ++i)
    40             if(c1[i] == 0)
    41             {
    42                 printf("%d\n", i);
    43                 break;
    44             }
    45         if(i == _max+1)
    46             printf("%d\n", i);
    47     }
    48     return 0;
    49 }

     http://acm.hdu.edu.cn/showproblem.php?pid=2082

    找单词:

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 int c1[51],c2[51];
     6 int a[27];
     7 int main()
     8 {
     9     int N;
    10     cin>>N;
    11     while(N--)
    12     {
    13         int i,j,k;
    14         for(i=1;i<=26;i++)
    15         {
    16             cin>>a[i];
    17         }
    18         memset(c1,0,sizeof(c1));
    19         memset(c2,0,sizeof(c2));
    20         c1[0]=1;//相当于用x^0去乘后面的多项式
    21         for(i=1;i<=26;i++)//要乘以26个多项式
    22         {
    23             for(j=0;j<=50;j++)//c1的各项指数
    24             {
    25                 for(k=0;j+i*k<=50&&k<=a[i];k++)//k*i表示被乘多项式各项的指数(x^(0*i)+x^(1*i)+x^(2*i)+...)
    26                 {                                                              //指数相加得j+k*i,加多少只取决于c1[j]的系数,因为被乘多项式的各项系数均1
    27                     c2[j+i*k]+=c1[j];
    28                 }
    29             }
    30             for(j=0;j<=50;j++)
    31             {
    32                 c1[j]=c2[j];
    33                 c2[j]=0;
    34             }
    35         }
    36         int sum=0;
    37         for(i=1;i<=50;i++)sum+=c1[i];
    38         cout<<sum<<endl;
    39     }
    40     return 0;
    41 }

    http://acm.hdu.edu.cn/showproblem.php?pid=1171

    Big Event in HDU:

    (完全是按照上面的模板来写的):

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 int value[77],num[77];
     6 int c1[777777],c2[777777];
     7 int main()
     8 {
     9     int n;
    10     int i,j,k;
    11     while(cin>>n&&n>=0)
    12     {
    13         int sum=0;
    14         for( i=1;i<=n;i++)
    15         {
    16             cin>>value[i]>>num[i];
    17             sum+=value[i]*num[i];
    18         }
    19         memset(c1,0,sum*(sizeof(c1[1])));
    20         memset(c2,0,sum*(sizeof(c2[1])));
    21         c1[0]=1;
    22         for(i=1;i<=n;i++)
    23         {
    24             for(j=0;j<=sum;j++)
    25             {
    26                 for(k=0;j+k*value[i]<=sum&&k<=num[i];k++)
    27                 {
    28                     c2[j+k*value[i]]+=c1[j];
    29                 }
    30             }
    31             for(j=0;j<=sum;j++)
    32             {
    33                 c1[j]=c2[j];
    34                 c2[j]=0;
    35             }
    36         }
    37         for(i=sum/2;i>=0;i--)
    38         {
    39             if(c1[i]!=0)break;
    40         }
    41         cout<<sum-i<<' '<<i<<endl;
    42     }
    43     return 0;
    44 }

     http://acm.hdu.edu.cn/showproblem.php?pid=2152

    水果问题:

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 int c1[117],c2[117];
     6 int a[117],b[117];
     7 int main()
     8 {
     9     int n,m;
    10     int i,j,k;
    11     while(cin>>n>>m)
    12     {
    13         for(i=0;i<n;i++)
    14         {
    15             cin>>a[i]>>b[i];
    16         }
    17         memset(c1,0,sizeof(c1));
    18         memset(c2,0,sizeof(c2));
    19         for(i=a[0];i<=b[0];i++)c1[i]=1;
    20         for(i=1;i<n;i++)
    21         {
    22             for(j=0;j<=m;j++)
    23             {
    24                 for(k=a[i];k+j<=m&&k<=b[i];k++)//由题目要求进行限制,最关键的一步
    25                 {
    26                     c2[k+j]+=c1[j];
    27                 }
    28             }
    29             for(j=0;j<=m;j++)
    30             {
    31                 c1[j]=c2[j];
    32                 c2[j]=0;
    33             }
    34         }
    35         cout<<c1[m]<<endl;
    36     }
    37     return 0;
    38 }

    举了这么多例子,无非是想说母函数的应用变化多端,但只要掌握了其原理,再根据模板进行修改,就行了,come on!!!

  • 相关阅读:
    jvisualm 结合 visualGC 进行jvm监控,并分析垃圾回收
    linux 查看服务器cpu 与内存配置
    arthas 使用总结
    selinux contexts 安全上下文的临时更改
    Android 8.1 Doze模式分析(五) Doze白名单及Debug方式
    Window 任意窗口置顶软件Window TopMost Control
    Android ApkToolPlus一个可视化的跨平台 apk 分析工具
    SVN Please execute the 'Cleanup' command.
    Android 如何在64位安卓系统中使用32位SO库
    Android cmd命令查看apk是32位还是64位?
  • 原文地址:https://www.cnblogs.com/wally/p/hdu1028_1085_1171_.html
Copyright © 2011-2022 走看看