HDU 1521 2082--母函数 数量n比较小

上一篇文章讲了母函数形式上的意义和构造方法

下面两篇文章讲一些代码实现和例子。

 

1.有限个物品的通解

 

for(int i=0;i<n;i++)
{
    for(int j=0;j<maxn;j++)
        for(int k=0;k<=a[i];k++)
            c2[j+value[i]*k]+=c1[j];//c2[j+value[i]*k]+=c1[j]/ji(k);  ji为预处理的阶乘
            memcpy(c1,c2,sizeof(c1));
            memset(c2,0,sizeof(c2));
}

上面代码参考了一个大佬博客

 

乍一看,不就很类似背包DP(应该是多重背包)的过程吗?

①value[i]代表各自物品对所求答案的贡献,通常为质量,对应背包各种物品的质量

②j是当前多项式的次数(已经取好的物品总量),对应背包剩余容量

③k是当前要取的当前物品个数(最大为这种物品的个数,对应最高次数

④+=因为有可能有不同方法得到同一个项  比如\large (1+x)(x+x^{^{2}}) =x^{3}+2x^{2}+x\large x^{2}有两种途径得到。

⑤至少需要两个数组,一个是c1存储答案,一个是c2存储当前下一个乘积得到的多项式系数

类似归并排序的思想,每次都要把c2复制到c1,c2清空

可能用到value数组,但如果价值都为1可以省略。

 

2.指数型母函数 HDU1521  排列组合

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
double a[130],b[130];//a 保存结果  b临时存
int num[130];
int jc(int p) 
{
	int cnt=1;
	for(int i=2;i<=p;i++)cnt*=i;
	
	return cnt;
}
int main()
{

	int x,y;
	while(cin>>x>>y)
	{
		for(int i=1;i<=x;i++)cin>>num[i];
	    memset(a,0,sizeof(a));
	    memset(b,0,sizeof(b));
	    a[0]=1;
		for(int i=1;i<=x;i++)//取第几个
		{
		
		    for(int j=0;j<=y;j++)//已经乘了的指数
		    {
			    for(int k=0;(k*1+j<=y)&&(k<=num[i]);k++)//每个物品对排列组合数贡献为1 
			    {
			    	b[k+j]+=a[j]/jc(k);//指数型母函数,需要多除以一个k!
			    }
		    } 
			for(int j=0;j<=y;j++)
			{
				a[j]=b[j];
				b[j]=0;
			}
		}
	
		printf("%.0lf\n",a[y]*jc(y));//不能直接cout,会WA
	}
	

return 0;
}

 

3.普通型母函数+value带权值  HDU2082 找单词

每个单词有权值,比如A权值为1,B为2...   注意此时第三层for循环,k应该带系数

求总和而不是单种单词的总和,所以最后要for循环加一遍

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[60],b[60];//a 保存结果  b临时存 
int main()
{
int n;
cin>>n;
while(n--)
{
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	a[0]=1;
	int x;
	for(int i=1;i<=26;i++)
	{
		scanf("%d",&x);
		for(int j=0;j<=50;j++)//已经求好的指数
		{
			for(int k=0;k<=x&&(j+k*i<=50);k++)//每种单词带的指数 
			{
				b[i*k+j]+=a[j];//这里k前面就要乘了
			}
		} 
			for(int j=0;j<=50;j++)
			{
				a[j]=b[j];
				b[j]=0;
			}
		
	}
		ll ans=0;
		for(int i=1;i<=50;i++)
		{
			ans+=a[i];
		}
		
	
	cout<<ans<<endl;
}
return 0;
}

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值