zoukankan      html  css  js  c++  java
  • HDU 1028(母函数)整数划分

    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
    ", i);
    43                 break;
    44             }
    45         if(i == _max+1)
    46             printf("%d
    ", 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!!!

     my  ac

    #include<iostream>
    #include<cmath>
    #define N 100000
    using namespace std;
    int main()
    {
        int i,j,n,k;
        int c1[N],c2[N];
        while(cin>>n)
        {
            if(n==0)
            cout<<"0"<<endl;
            else
            {
                for(i=0;i<=n;i++)
                {
                    c1[i]=1;
                    c2[i]=0;
                }
                
                for(i=2;i<=n;i++)
                {
                    for(j=0;j<=n;j++)
                    {
                        for(k=0;k+j<=n;k+=i)
                          c2[k+j]+=c1[j];
                    }
                    for(j=0;j<=n;j++)
                    {
                        c1[j]=c2[j];
                        c2[j]=0;
                    }
                }
            cout<<c1[n]<<endl;    
                
            }
            
        }
        return 0;
    }
  • 相关阅读:
    How does Android, PHP, SQL, JSON, and Remote Databases work together?
    Gson Json
    Protocol Android
    AsyncTask、多线程及线程通信
    线程-Android
    HTTP请求-Android
    Make Your First Android App
    Git版本控制软件结合GitHub从入门到精通常用命令学习手册
    正向代理设置
    vscode 调试 react 项目
  • 原文地址:https://www.cnblogs.com/hezixiansheng8/p/3710907.html
Copyright © 2011-2022 走看看