NOIP2012普及组 T3 摆花(加强版)
2017-07-02 18:23
204 查看
【题目大意】
用 n 种花摆共 m 盆花,每盆仅能摆一种花,不分每种花、每盆花的顺序,第 i 种花可以不摆,最多摆 ai 盆,求方案数。
【输入格式】
共 2 行。第一行包含两个正整数 n 和 m,中间用一个空格隔开。第二行有 n 个整数,每两个整数之间用一个空格隔开,依次表示 a1、a2、……an 。
【输出格式】
一个整数,方案数对1000007取模的结果。
【数据范围】
对于10%的数据, 0<n,m≤50,0≤ai≤50
对于30%的数据, 0<n,m≤100,0≤ai≤100
对于60%的数据,0<n,m≤2333,0≤ai≤2333
对于100%的数据,0<n,m≤8848,0≤ai≤8848
网上说O(nm2)是背包的,是因为
对于一个给定了背包容量、物品费用、物品间相互关系(分组、依赖等)的背包问题,除了再给定每个物品的价值后求可得到的最大价值外,还可以得到装满背包或将背包装至某一指定容量的方案总数。
对于这类改变问法的问题,一般只需将状态转移方程中的 max 改成 sum 即可。——《背包九讲》
不过,严格来说这不能算是背包,叫递推可能好点儿,因为动态规划专指解决最优化问题(求最大\小\快\慢)。当然分析时以及递推式与背包很像。
fi,j=∑k=0i−1∑l=j−aij−1fk,l
也就是用前0~i-1种花摆j-ai盆时用第i-1种花摆第j-ai盆(则第 i 种花摆ai盆)的方案数,加上用前0~i-1种花摆j-ai+1盆时用第i-1种花摆第j-ai+1盆(第 i 种花摆ai-1盆)的方案数,一直到用前0~i-1种花摆j-1盆时用第i-1种花摆第j-1盆的方案数。
另外,在上面的递推式中,如果j<ai,递推式变为
fi,j=∑k=0i−1∑l=0j−1fk,l
边界条件,f0,0=1,结果是fi,j=∑ni=1fi,m
虽说这方法很low但是我最早是通过这个方法推出O(nm)的方法的嗯。
fi,j=∑k=j−aij−1fi−1,k
也就是(当第 i 种花摆ai盆时)用前i-1种花摆j-ai盆的方案数,加上(当第 i 种花摆ai-1盆时)用前i-1种花摆j-ai+1盆的方案数,一直到(当第 i 种花只摆1盆时)用前i-1种花摆j-1盆的方案数。
边界变为fi,0=1,结果是fi,j。
在一维情况下,例如求f3到f8之和。用sumx表示∑xi=0fi,很明显f3到f8之和=sum8−sum2。
推广到二维情况,用sumx,y表示∑xi=0∑yj=0fi,j,如求f1,2到f4,5的和(蓝色区域)。
![](http://img.blog.csdn.net/20170708155123559?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ290b2phdmE5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
很明显,蓝色部分的和=图中整个区域-橙色区域-绿色区域+屎黄色区域=sum4,5−sum4,1−sum0,5+sum0,1。
不过这题的前缀和倒简单一点。当j<ai时,fi,j=∑k=0i−1∑l=0j−1fk,l=sumi−1,j−1
而当j≥ai时
fi,j=∑k=0i−1∑l=j−aij−1fk,l注意到k是从0开始的,因此只要把 l 这层拆开。
fi,j=∑k=0i−1∑l=0j−1fk,l−∑k=0i−1∑l=0j−ai−1fk,l=sumi−1,j−1−sumi−1,j−ai−1
![](http://img.blog.csdn.net/20170708161205703?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ290b2phdmE5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
也就是fi,j等于整个蓝色区域减去浅蓝色区域(不要在意为什么图片的字体不同)。
还有一点是更新sum数组。
![](http://img.blog.csdn.net/20170708165146859?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ290b2phdmE5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
如图,sum6,5=sum4,6+sum5,5−sum4,5+f6,5。sum6,5等于f6,5和f6,5的左方和上方的所有数之和。用前缀和的思想,f6,5的左方和上方的所有数一部分是sum4,6,另一部分是sum5,5,而重叠的部分是sum4,5。
所以sumi,j=sumi−1,j+sumi,j−1−sumi−1,j−1+fi,j
当j<ai时,sumi,j=sumi−1,j+sumi,j−1−sumi−1,j−1+sumi−1,j−1=sumi−1,j+sumi,j−1
当j≥ai时,sumi,j=sumi−1,j+sumi,j−1−sumi−1,j−1+sumi−1,j−1−sumi−1,j−ai−1=sumi−1,j+sumi,j−1−sumi−1,j−ai−1
这样就可以吃掉 f 数组了。
由于是从O(n2m2)的方法推出来,所以sum0,0=f0,0=1,由于是前缀和,同理要把sumi,0与sum0,i都清成1。
绕了一大圈,我倒发现这个递推式本不用这么复杂的推导。用sumi,j表示用前 i 种花摆前0~j盆花(不摆花+只摆第1盆花+摆前2盆花+…+摆前j盆花)的方案数。不用第 i 种花摆第 j 盆的方案数为sumi−1,j。用第 i 种花摆第 j 盆的方案数为sumi,j−1,但当j≥ai时,还要减去用前 i-1 种花摆前0~j-ai-1盆花的方案数(因为前提是用第 i 种花摆第 j 盆,当用前 i-1 种花摆前 j-ai-1盆花时,就要摆第 i 种花ai+1盆;当用前 i-1 种花摆前 j-ai-2盆花时,就要摆第 i 种花ai+2盆,以此类推)。
在这个数据范围下时间复杂度是可以承受的,但空间炸了。可以注意到无论是sumi,j=sumi−1,j+sumi,j−1还是sumi,j=sumi−1,j+sumi,j−1−sumi−1,j−ai−1的 i 那层只有 i 和 i-1两种情况,所以用滚动数组可以解决空间问题。
写完后我联系到01背包的空间优化方法本以为有一维数组的做法,但思虑再三发现不行。
![](http://img.blog.csdn.net/20170714084726590?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ290b2phdmE5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
在01背包的空间优化中,求灰色格的值需要用到的两个值都在灰色格的左边和上边。
![](http://img.blog.csdn.net/20170708182519242?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ290b2phdmE5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
但是在本题中,根据递推式,上图中&%#¥¥#@%……&¥总之就是不行啦求大佬看一下怎么说清楚
感谢陈老师~
用 n 种花摆共 m 盆花,每盆仅能摆一种花,不分每种花、每盆花的顺序,第 i 种花可以不摆,最多摆 ai 盆,求方案数。
【输入格式】
共 2 行。第一行包含两个正整数 n 和 m,中间用一个空格隔开。第二行有 n 个整数,每两个整数之间用一个空格隔开,依次表示 a1、a2、……an 。
【输出格式】
一个整数,方案数对1000007取模的结果。
【数据范围】
对于10%的数据, 0<n,m≤50,0≤ai≤50
对于30%的数据, 0<n,m≤100,0≤ai≤100
对于60%的数据,0<n,m≤2333,0≤ai≤2333
对于100%的数据,0<n,m≤8848,0≤ai≤8848
〇、网上说法的一些问题
加了一些特别大的数据是因为网上大部分做法都是O(nm2),没法对付n, m上千的情况。本题有时间O(nm),空间O(n+2m)的做法。网上说O(nm2)是背包的,是因为
对于一个给定了背包容量、物品费用、物品间相互关系(分组、依赖等)的背包问题,除了再给定每个物品的价值后求可得到的最大价值外,还可以得到装满背包或将背包装至某一指定容量的方案总数。
对于这类改变问法的问题,一般只需将状态转移方程中的 max 改成 sum 即可。——《背包九讲》
不过,严格来说这不能算是背包,叫递推可能好点儿,因为动态规划专指解决最优化问题(求最大\小\快\慢)。当然分析时以及递推式与背包很像。
一、10%,时间O(n2m2),空间O(nm)
最初想的时候把状态搞复杂了……用fi,j表示用前 i 种花摆前 j 盆时用第 i 种花摆第 j 盆,则可得递推式fi,j=∑k=0i−1∑l=j−aij−1fk,l
也就是用前0~i-1种花摆j-ai盆时用第i-1种花摆第j-ai盆(则第 i 种花摆ai盆)的方案数,加上用前0~i-1种花摆j-ai+1盆时用第i-1种花摆第j-ai+1盆(第 i 种花摆ai-1盆)的方案数,一直到用前0~i-1种花摆j-1盆时用第i-1种花摆第j-1盆的方案数。
另外,在上面的递推式中,如果j<ai,递推式变为
fi,j=∑k=0i−1∑l=0j−1fk,l
边界条件,f0,0=1,结果是fi,j=∑ni=1fi,m
f[0][0] = 1; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) for (k = 0; k < i; k++) for (l = max(0, j - a[i]); l < j; l++) (f[i][j] += f[k][l]) %= mod; for (i = 1; i <= n; i++) (ans += f[i][m]) %= mod;
虽说这方法很low但是我最早是通过这个方法推出O(nm)的方法的嗯。
二、30%,时间O(nm2),空间O(nm)
如果fi,j只是表示用前 i 种花摆前 j 盆(不一定要用第 i 种花),递推式便缩减成fi,j=∑k=j−aij−1fi−1,k
也就是(当第 i 种花摆ai盆时)用前i-1种花摆j-ai盆的方案数,加上(当第 i 种花摆ai-1盆时)用前i-1种花摆j-ai+1盆的方案数,一直到(当第 i 种花只摆1盆时)用前i-1种花摆j-1盆的方案数。
边界变为fi,0=1,结果是fi,j。
for (i = 0; i <= n; i++) f[i][0] = 1; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) for (k = max(0, j-a[i]); k < j; k++) (f[i][j] += f[i - 1][k]) %= mod; ans = f [m];
三、60%,时间O(nm),空间O(nm)
推出这种方法的思路,一种是O(n2m2)的方法加二维前缀和。在一维情况下,例如求f3到f8之和。用sumx表示∑xi=0fi,很明显f3到f8之和=sum8−sum2。
f | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|
很明显,蓝色部分的和=图中整个区域-橙色区域-绿色区域+屎黄色区域=sum4,5−sum4,1−sum0,5+sum0,1。
不过这题的前缀和倒简单一点。当j<ai时,fi,j=∑k=0i−1∑l=0j−1fk,l=sumi−1,j−1
而当j≥ai时
fi,j=∑k=0i−1∑l=j−aij−1fk,l注意到k是从0开始的,因此只要把 l 这层拆开。
fi,j=∑k=0i−1∑l=0j−1fk,l−∑k=0i−1∑l=0j−ai−1fk,l=sumi−1,j−1−sumi−1,j−ai−1
也就是fi,j等于整个蓝色区域减去浅蓝色区域(不要在意为什么图片的字体不同)。
还有一点是更新sum数组。
如图,sum6,5=sum4,6+sum5,5−sum4,5+f6,5。sum6,5等于f6,5和f6,5的左方和上方的所有数之和。用前缀和的思想,f6,5的左方和上方的所有数一部分是sum4,6,另一部分是sum5,5,而重叠的部分是sum4,5。
所以sumi,j=sumi−1,j+sumi,j−1−sumi−1,j−1+fi,j
当j<ai时,sumi,j=sumi−1,j+sumi,j−1−sumi−1,j−1+sumi−1,j−1=sumi−1,j+sumi,j−1
当j≥ai时,sumi,j=sumi−1,j+sumi,j−1−sumi−1,j−1+sumi−1,j−1−sumi−1,j−ai−1=sumi−1,j+sumi,j−1−sumi−1,j−ai−1
这样就可以吃掉 f 数组了。
由于是从O(n2m2)的方法推出来,所以sum0,0=f0,0=1,由于是前缀和,同理要把sumi,0与sum0,i都清成1。
sum[0][0] = 1; for (i = 1; i <= n; i++) sum[i][0] = 1; for (i = 1; i <= m; i++) sum[0][i] = 1; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) if (a[i] <= j) sum[i][j] = (sum[i - 1][j] + sum[i][j - 1]) % mod; else sum[i][j] = (sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - a[i] - 1] + mod) % mod; ans = (sum [m] - sum [m - 1] + mod) % mod;
绕了一大圈,我倒发现这个递推式本不用这么复杂的推导。用sumi,j表示用前 i 种花摆前0~j盆花(不摆花+只摆第1盆花+摆前2盆花+…+摆前j盆花)的方案数。不用第 i 种花摆第 j 盆的方案数为sumi−1,j。用第 i 种花摆第 j 盆的方案数为sumi,j−1,但当j≥ai时,还要减去用前 i-1 种花摆前0~j-ai-1盆花的方案数(因为前提是用第 i 种花摆第 j 盆,当用前 i-1 种花摆前 j-ai-1盆花时,就要摆第 i 种花ai+1盆;当用前 i-1 种花摆前 j-ai-2盆花时,就要摆第 i 种花ai+2盆,以此类推)。
四、100%,时间O(nm),空间O(n+2m)
呼我为什么要把那种复杂的分析方法写上……在这个数据范围下时间复杂度是可以承受的,但空间炸了。可以注意到无论是sumi,j=sumi−1,j+sumi,j−1还是sumi,j=sumi−1,j+sumi,j−1−sumi−1,j−ai−1的 i 那层只有 i 和 i-1两种情况,所以用滚动数组可以解决空间问题。
sum[0][0] = sum[1][0] = 1; for (i = 1; i <= m; i++) sum[0][i] = 1; bool t; for (i = 1, t = 1; i <= n; i++, t = !t) for (j = 1; j <= m; j++) if (j <= a[i]) sum[t][j] = (sum[t][j - 1] + sum[!t][j]) % mod; else sum[t][j] = (sum[t][j - 1] + sum[!t][j] - sum[!t][j - a[i] - 1] + mod) % mod;
写完后我联系到01背包的空间优化方法本以为有一维数组的做法,但思虑再三发现不行。
在01背包的空间优化中,求灰色格的值需要用到的两个值都在灰色格的左边和上边。
但是在本题中,根据递推式,上图中&%#¥¥#@%……&¥总之就是不行啦求大佬看一下怎么说清楚
感谢陈老师~
相关文章推荐
- NOIP2012 普及组 T3 摆花——S.B.S.
- 摆花 NOIP2012普及
- 【noip2012普及】摆花
- NOIP 2012 - 普及组 摆花 递推 重庆一中高2018级竞赛班第六次测试 2016.7.31 Problem 3
- 【NOIP2012普及组】摆花 (递推)
- [NOIP2012普及组]摆花
- Noip2012 普及组 第三题 摆花
- 【NOIP2012普及组】摆花(递推)
- 洛谷P1077 [NOIP2012普及组]摆花 [2017年四月计划 动态规划14]
- 摆花(2012Noip普及组第3题)
- 【NOIP2012普及】摆花
- [普及] NOIP 2012 摆花
- NOIP2012普及组 摆花(重庆一中高2018级信息学竞赛测验6) 解题报告
- C. 【NOIP2012普及组真题】 摆花
- 【NOIP2012普及组】摆花
- NOIP2012普及组-摆花
- [Noip2012普及组]摆花
- Cpp环境【NOIP2012普及组】【Vijos1792】摆花
- (2050): 【NOIP2012普及组】摆花
- NOIP2017棋盘(普及T3)