母函数:poj 1014 Dividing

来源:互联网 发布:阿里云认证有用吗 编辑:程序博客网 时间:2024/06/04 18:53

题目大意

告诉我们价值为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;}
1 0
原创粉丝点击