母函数实例

本篇博客主要讲解母函数的具体实例,如果你不会母函数这两篇博客你可以看看看:

母函数的定义以及整数拆分模板 母函数(Generating function)详解和母函数 入门 + 模板
1.题目:Ignatius and the Princess III
题意:给你一个数n,从1到n的这些数用无穷多个,问你n有多少方法构成。
代码:

#include<bits/stdc++.h>
using namespace std;
#define maxn  130
int c1[maxn],c2[maxn];
int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        for(int i = 0; i <= n; i++)
        {
            c1[i] = 1;
            c2[i] = 0;
        }
        for(int i = 2; i <= n; i++) //第几个括号
        {
            for(int j = 0; j <= n; j++) //当前项的每一项
            {
                for(int k = 0; j + k <= n; k += i) //下一项的每一项
                {
                    c2[k+j] += c1[j];
                }
            }
            for(int j = 0; j <= n; j++) //初始化当前项
            {
                c1[j] = c2[j];
                c2[j] = 0;
            }
        }
        cout<<c1[n]<<endl;
    }
    return 0;
}

2.题目:Square Coins

题意:给你1, 4, 9,16, 25,36……289这些有无限个,问你有多少中方法构成n
代码:

#include<bits/stdc++.h>
using namespace std;
#define maxn  310
int c1[maxn],c2[maxn];
int main()
{
    int n;
    while(scanf("%d", &n) && n != 0)
    {
        for(int i = 0; i <= n; i++)
        {
            c1[i] = 1;
            c2[i] = 0;
        }
        for(int i = 2; i*i <= n; i++) //第几个括号
        {
            for(int j = 0; j <= n; j++) //当前项的每一项
            {
                for(int k = 0; j + k <= n; k += i*i) //下一项的每一项
                {
                    c2[k+j] += c1[j];
                }
            }
            for(int j = 0; j <= n; j++) //初始化当前项
            {
                c1[j] = c2[j];
                c2[j] = 0;
            }
        }
        cout<<c1[n]<<endl;
    }
    return 0;
}

3.题目:Holding Bin-Laden Captive!

题意:给你1,2,5三个数的个数有分别有num1,num2, num3个,问 这三个数不能构成的最小的数。
思想:利用母函数求出所以能构成的数,然后进行筛选,输出最小的一个不能构成的。
代码:

#include<bits/stdc++.h>
using namespace std;
#define maxn  8005
int c1[maxn],c2[maxn];
int main()
{
    int num1, num2, num3, num;
    while(scanf("%d %d %d", &num1, &num2, &num3) )
    {
        if(!num1 && !num2 && !num3)break;
        for(int i = 0; i <= num1; i++)
        {
            c1[i] = 1;
        }
        num = num2*2+num3*5+num1;
        for(int j = 0; j <= num1; j ++) //当前项的每一项
        {
            for(int k = 0; k <= num2*2; k += 2) //下一项的每一项
            {
                c2[k+j] += c1[j];
            }
        }
        for(int j = 0; j <= num1+2*num2; j++) //初始化当前项
        {
            c1[j] = c2[j];
            c2[j] = 0;
        }
        for(int j = 0; j <= num1+2*num2; j++) //当前项的每一项
        {
            for(int k = 0; k <= num3*5; k += 5) //下一项的每一项
            {
                c2[k+j] += c1[j];
            }
        }
        for(int j = 0; j <= num; j++) //初始化当前项
        {
            c1[j] = c2[j];
            c2[j] = 0;
        }
        int flag  = -1;
        for(int i = 1; i <= num; i++)
        {

            if(!c1[i])
            {
                flag = i;
                break;
            }

        }
        if(flag == -1)cout<<num+1<<endl;
        else cout<<flag<<endl;
    }
    return 0;
}

4.题目:Big Event in HDU

题意:跟你n项数据,每项数据包括一个属的值和这个数的个数,尽量把这些数平分,每一个数不能分割,如果实在不能均分,那么就输出A比B稍微大的那一个。
思想:还是利用母函数,求出每一个数的构成方法,然后从中间开始枚举。
代码:

#include<bits/stdc++.h>
using namespace std;
#define maxn 250005
int c1[maxn], c2[maxn];
int v[55], m[55];
int main()
{
    int n;
    while(cin>>n && n > 0)
    {
        int sum = 0;
        for(int i = 1; i <= n; i++)
        {
            cin>>v[i]>>m[i];
            sum += v[i] * m[i];
        }
        memset(c1, 0, sizeof(c1));
        memset(c2, 0, sizeof(c2));
        for(int i = 0; i <= v[1]*m[1]; i += v[1])
        {
            c1[i] = 1;
        }
        int len = v[1]*m[1];
        for(int i = 2; i <= n; i++) //括号的个数
        {
            for(int j = 0; j <= len; j++) //当前的项数
            {
                for(int k = 0; k <= v[i]*m[i]; k += v[i]) //下一项
                {
                    c2[k+j] += c1[j];
                }
            }
            len += v[i]*m[i];
            for(int j = 0; j <= len; j++)
            {
                c1[j] = c2[j];
                c2[j] = 0;
            }
        }
        for(int i = sum / 2; i >= 0; i--)
        {
            if(c1[i] != 0)
            {
                cout<<sum - i<<" "<<i<<endl;
                break;
            }
        }
    }
    return 0;
}

点赞