题目大意
告诉我们价值为1,2,3,4,5,6珠宝的个数,判断能否将珠宝依价值均分。
解题思路
类似整数拆分成和相等的两部分,很容易想到母函数。
所谓母函数,我的理解是幂级数。
我们称函数G(x)是序列a0,a1,a2,…,的母函数。
通常情况下会构造母函数为多个子函数的乘积,例如
这样的多项式乘积就会赋予数学意义,比如说整数拆分、分珠宝等一系列问题,1014这道题就属于母函数问题。
这道题有价值1,2,3,4,5,6的珠宝,分别告诉对应的数量,问最后能不能依价值均分,设总价值value,也就是母函数结果中x^value/2的系数是否不为0。
还有一个问题,某价值珠宝数目n很大时,三重循环很容易超时,需要剪枝优化,网上有这样一个定理:
对于任意一种珠宝的个数,如果n>=8时,可以将n改写为11(n为奇数)或12(n为偶数)
定理不会证明,日后咀嚼。
网上有另外一个定理+证明,discuss讨论区,look look
参考代码+部分注释
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <vector>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 6e3+10;
int a[10],c1[maxn],c2[maxn];
int judge(int n)//剪枝操作,对某一价值珠宝数目n>=8的处理,避免TLE
{
if(n&1) return 11;
return 12;
}
int solve(int value)//返回x^(value/2)的系数
{
value/=2; //总价格的一半
memset(c1,0,sizeof(c1));//c1用于存储最终结果
memset(c2,0,sizeof(c2));//c2用于保留中间结果
for(int i=0;i<=a[1];i++) c1[i]=1;//第一个表达式初始化
for(int i=2;i<=6;i++){
for(int j=0;j<=value;j++)//遍历第二个表达式的指数,找到对应系数非0的数
if(c1[j]){
for(int k=0;k+j<=value&&k<=i*a[i];k+=i)//后一表达式遍历
c2[j+k]+=c1[j];
}
memcpy(c1,c2,sizeof(c2));
memset(c2,0,sizeof(c2));
}
if(c1[value]) return c1[value];
return 0;
}
int main()
{
// freopen("input.txt","r",stdin);
int count=1;
while(1){
int sum=0;
for(int i=1;i<=6;i++){
cin>>a[i];
if(a[i]>=8) a[i]=judge(a[i]);
sum+=i*a[i];
}
if(sum==0) break;//跳出循环
else if(sum&1) cout<<"Collection #"<<count++<<":"<<endl<<"Can't be divided."<<endl;//剪枝操作,奇数肯定不能均分
else{
cout<<"Collection #"<<count++<<":"<<endl;
if(solve(sum)) cout<<"Can be divided."<<endl;
else cout<<"Can't be divided."<<endl;
}
cout<<endl;//注意每组数据之间有一个空行
}
return 0;
}