本篇博客主要讲解母函数的具体实例,如果你不会母函数这两篇博客你可以看看看:
母函数的定义以及整数拆分模板 母函数(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;
}