当前位置: 代码迷 >> 综合 >> HDU 2152 Fruit (母函数+模板)
  详细解决方案

HDU 2152 Fruit (母函数+模板)

热度:26   发布时间:2023-11-17 14:36:53.0

转眼到了收获的季节,由于有TT的专业指导,Lele获得了大丰收。特别是水果,Lele一共种了N种水果,有苹果,梨子,香蕉,西瓜……不但味道好吃,样子更是好看。 

于是,很多人们慕名而来,找Lele买水果。 

甚至连大名鼎鼎的HDU ACM总教头 lcy 也来了。lcy抛出一打百元大钞,"我要买由M个水果组成的水果拼盘,不过我有个小小的要求,对于每种水果,个数上我有限制,既不能少于某个特定值,也不能大于某个特定值。而且我不要两份一样的拼盘。你随意搭配,你能组出多少种不同的方案,我就买多少份!" 

现在就请你帮帮Lele,帮他算一算到底能够卖出多少份水果拼盘给lcy了。 

注意,水果是以个为基本单位,不能够再分。对于两种方案,如果各种水果的数目都相同,则认为这两种方案是相同的。 

最终Lele拿了这笔钱,又可以继续他的学业了~ 
Input
本题目包含多组测试,请处理到文件结束(EOF)。 
每组测试第一行包括两个正整数N和M(含义见题目描述,0<N,M<=100) 
接下来有N行水果的信息,每行两个整数A,B(0<=A<=B<=100),表示至少要买该水果A个,至多只能买该水果B个。 
Output
对于每组测试,在一行里输出总共能够卖的方案数。 
题目数据保证这个答案小于10^9 
Sample Input
2 3
1 2
1 2
3 5
0 3
0 3
0 3
Sample Output
2
12

题解:

比赛的时候用dfs+剪枝+二分tle了无数遍的一道题。。比完赛才知道有一种东西叫母函数,是一个模板。。然后就百度啊百度,没看懂。。问同学说只要搜一个模板套的去就好了。。真是神奇的一题,笔记笔记

以下是搜到的内容:

附上神犇博客讲解:http://blog.csdn.net/xiaofei_it/article/details/17042651   本题讲解:http://blog.csdn.net/xiaofei_it/article/details/17042497

然后是要笔记的内容:

通用模板:

//为计算结果,b为中间结果。
int a[MAX],b[MAX];
//初始化a
memset(a,0,sizeof(a));
a[0]=1;
for (int i=1;i<=17;i++)//循环每个因子
{memset(b,0,sizeof(b));for (int j=n1[i];j<=n2[i]&&j*v[i]<=P;j++)//循环每个因子的每一项for (int k=0;k+j*v[i]<=P;k++)//循环a的每个项b[k+j*v[i]]+=a[k];//把结果加到对应位memcpy(a,b,sizeof(b));//b赋值给a
}
讲解:

K对应具体问题中物品的种类数。

v[i]表示该乘积表达式第i个因子的权重,对应于具体问题的每个物品的价值或者权重。

n1[i]表示该乘积表达式第i个因子的起始系数,对应于具体问题中的每个物品的最少个数,即最少要取多少个。

n2[i]表示该乘积表达式第i个因子的终止系数,对应于具体问题中的每个物品的最多个数,即最多要取多少个。

P是可能的最大指数。拿钞票组合这题来说,如果要求15元有多少组合,那么P就是15;如果问最小的不能拼出的数值,那么P就是所有钱加起来的和

如果n2是无穷,那么第二层循环条件j<=n2[i]可以去掉。


最后结果为a[p];


如何提高效率?

用一个last变量记录目前最大的指数,这样只需要在0..last上进行计算。

这里给出第二个模板:

//初始化a,因为有last,所以这里无需初始化其他位
a[0]=1;
int last=0;
for (int i=0;i<K;i++)
{int last2=min(last+n[i]*v[i],P);//计算下一次的lastmemset(b,0,sizeof(int)*(last2+1));//只清空b[0..last2]for (int j=n1[i];j<=n2[i]&&j*v[i]<=last2;j++)//这里是last2for (int k=0;k<=last&&k+j*v[i]<=last2;k++)//这里一个是last,一个是last2b[k+j*v[i]]+=a[k];memcpy(a,b,sizeof(int)*(last2+1));//b赋值给a,只赋值0..last2last=last2;//更新last
}

详情请看神犇博客qaq我只是会套
这题我的代码:

#include<iostream> #include<stdio.h> #include<string> #include<cstring> #include<map> #include<queue> #include<stack> #include<algorithm> #include<math.h> #include<deque> #include<stack> using namespace std; int n1[105]; int n2[105]; int a[205]; int b[205]; int main() {int m,n,i,j,k;while(scanf("%d%d",&n,&m)!=EOF){for(i=0;i<n;i++)scanf("%d%d",&n1[i],&n2[i]);memset(a,0,sizeof(a));a[0]=1;for(i=0;i<n;i++)//循环每个因子{memset(b,0,sizeof(b));for(j=n1[i];j<=n2[i]&&j<=m;j++)//循环每个因子的每一项for(k=0;k+j<=m;k++)//循环a的每个项b[k+j]+=a[k];//把结果加到对应位memcpy(a,b,sizeof(b));//b赋值给a}printf("%d\n",a[m]);}return 0; }