转眼到了收获的季节,由于有TT的专业指导,Lele获得了大丰收。特别是水果,Lele一共种了N种水果,有苹果,梨子,香蕉,西瓜……不但味道好吃,样子更是好看。
于是,很多人们慕名而来,找Lele买水果。
甚至连大名鼎鼎的HDU ACM总教头 lcy 也来了。lcy抛出一打百元大钞,"我要买由M个水果组成的水果拼盘,不过我有个小小的要求,对于每种水果,个数上我有限制,既不能少于某个特定值,也不能大于某个特定值。而且我不要两份一样的拼盘。你随意搭配,你能组出多少种不同的方案,我就买多少份!"
现在就请你帮帮Lele,帮他算一算到底能够卖出多少份水果拼盘给lcy了。
注意,水果是以个为基本单位,不能够再分。对于两种方案,如果各种水果的数目都相同,则认为这两种方案是相同的。
最终Lele拿了这笔钱,又可以继续他的学业了~
于是,很多人们慕名而来,找Lele买水果。
甚至连大名鼎鼎的HDU ACM总教头 lcy 也来了。lcy抛出一打百元大钞,"我要买由M个水果组成的水果拼盘,不过我有个小小的要求,对于每种水果,个数上我有限制,既不能少于某个特定值,也不能大于某个特定值。而且我不要两份一样的拼盘。你随意搭配,你能组出多少种不同的方案,我就买多少份!"
现在就请你帮帮Lele,帮他算一算到底能够卖出多少份水果拼盘给lcy了。
注意,水果是以个为基本单位,不能够再分。对于两种方案,如果各种水果的数目都相同,则认为这两种方案是相同的。
最终Lele拿了这笔钱,又可以继续他的学业了~
每组测试第一行包括两个正整数N和M(含义见题目描述,0<N,M<=100)
接下来有N行水果的信息,每行两个整数A,B(0<=A<=B<=100),表示至少要买该水果A个,至多只能买该水果B个。
题目数据保证这个答案小于10^9
2 3 1 2 1 2 3 5 0 3 0 3 0 3
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; }