母函数:poj 1014 Dividing

本文介绍了一种通过母函数解决珠宝均分问题的方法。利用多项式乘积的数学意义,构造母函数并优化循环,判断特定价值的珠宝能否被均匀分配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

告诉我们价值为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

http://poj.org/showmessage?message_id=342382

参考代码+部分注释

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值