51Nod1957 有限背包计数问题
这题还挺有意思……
先贴一波出题人的题解……
(啥你说你看不见?看来你还没过啊,等着A了再看或者乖乖花点头盾好了……)
然后是我的做法……思想都是一样的,只是细节不一样而已……
令$B=\lceil \sqrt{n}\rceil$,把物品分$\ge B$和$<B$两类考虑:
对于大小$<B$的物品,直接用多重背包计数的方法去做即可,令$f[i][j]$表示使用前$i$个物品凑出$j$的方案数,显然有
\begin{align}f[i][j]=\sum_{k=0}^i f[i-1][j-ki]\end{align}
直接算的话时间肯定会爆炸,所以简单变形一下,得到
$f[i][j]=f[i][j-i]+f[i-1][j]-f[i-1][i(i+1)]$
应该不难理解,就是对上一个状态的转移区间做一下微调,加上右端点并减掉左端点。
这样每个状态的计算时间就变成$O(1)$了,而总共有$O(n\sqrt{n})$个状态,因此这部分的复杂度就是$O(n\sqrt{n})$。
对于大小$\ge B$的物品,显然这些物品是用不完的,直接当作完全背包处理即可。又因为这些物品最多使用$\lfloor \frac n B\rfloor$个,因此可以令$g[i][j]$表示强制只能使用大小$\ge B$的物品时用$i$个物品凑出$j$的方案数。
直接算不太好算,我们考虑给物品动态添加大小:
$g[i][j]=g[i-1][j-B]+g[i][j-i]$
前一种是添加一个大小为$B$的物品,后一种是把所有物品的大小都$+1$,应该不难看出来这样可以做到不重不漏地统计所有方案。
使用的物品数不会超过$\sqrt{n}$,因此状态数仍然是$O(n\sqrt{n})$,单次转移$O(1)$,这样后半部分的复杂度就也是$O(n\sqrt{n})$了。
最后合并两部分的结果即可,显然有
\begin{align}Ans=\sum_{i=0}^n f[n-i]\sum_{j=0}^{\lfloor\frac n B\rfloor}g[j][n-i]\end{align}
直接算是$O(n\sqrt{n})$的,如果在算$g$的时候顺便算一下$h[j]=\sum_i g[i][j]$的话可以降到$O(n)$,再加上分块DP的复杂度,总复杂度就是$O(n\sqrt{n})$。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=,p=;
int n,B,f[][maxn]={{}},g[][maxn]={{}},h[maxn]={},cur=,ans=;
int main(){
scanf("%d",&n);
B=(int)ceil(sqrt(n));
f[][]=g[][]=h[]=;
for(int i=;i*B<=n;i++){
cur^=;
for(int j=(i-)*B;j<i*B;j++)g[cur][j]=;
for(int j=i*B;j<=n;j++){
g[cur][j]=g[cur^][j-B];
if(j>=i)g[cur][j]=(g[cur][j]+g[cur][j-i])%p;
h[j]=(h[j]+g[cur][j])%p;
}
}
cur=;
for(int i=;i<B;i++){
cur^=;
for(int j=;j<=n;j++){
f[cur][j]=f[cur^][j];
if(j>=i){
f[cur][j]=(f[cur][j]+f[cur][j-i])%p;
if(j>=i*(i+))f[cur][j]=(f[cur][j]-f[cur^][j-i*(i+)])%p;
}
}
}
for(int i=;i<=n;i++)ans=(ans+(int)((long long)f[cur][i]*h[n-i]%p))%p;
if(ans<)ans+=p;
printf("%d",ans);
return ;
}
话说听说这题有多项式乘法加速的$O(n\log n)$做法,然而翻了翻51Nod的排行榜并没有看到写这种做法的……看了半天OEIS也没看懂怎么用多项式乘法加速,算了反正分块跑得也挺快我就用分块算了……
51Nod1957 有限背包计数问题的更多相关文章
- [51nod1597]有限背包计数问题
你有一个大小为n的背包,你有n种物品,第i种物品的大小为i,且有i个,求装满这个背包的方案数有多少 两种方案不同当且仅当存在至少一个数i满足第i种物品使用的数量不同 Input 第一行一个正整数n 1 ...
- 51Nod 有限背包计数问题 题解报告
首先这道题理论上是可以做到O(nlogn)的,因为OEIS上有一个明显可以用多项式乘法加速的式子 但是由于模数不是很兹磁,所以导致nlogn很难写 在这里说一下O(n*sqrt(n))的做法 首先我们 ...
- 2018.09.25 51nod1597 有限背包计数问题(背包+前缀和优化)
传送门 dp好题. 我认为原题的描述已经很清楚了: 你有一个大小为n的背包,你有n种物品,第i种物品的大小为i,且有i个,求装满这个背包的方案数有多少. 两种方案不同当且仅当存在至少一个数i满足第i种 ...
- 51nod 1597 有限背包计数问题 (背包 分块)
题意 题目链接 Sol 不会做啊AAA.. 暴力上肯定是不行的,考虑根号分组 设\(m = \sqrt{n}\) 对于前\(m\)个直接暴力,利用单调队列优化多重背包的思想,按\(\% i\)分组一下 ...
- 题解 51nod 1597 有限背包计数问题
题目传送门 题目大意 给出 \(n\),第 \(i\) 个数有 \(i\) 个,问凑出 \(n\) 的方案数. \(n\le 10^5\) 思路 呜呜呜,傻掉了... 首先想到根号分治,分别考虑 \( ...
- LOJ #6089. 小 Y 的背包计数问题
LOJ #6089. 小 Y 的背包计数问题 神仙题啊orz. 首先把数分成\(<=\sqrt n\)的和\(>\sqrt n\)的两部分. \(>\sqrt n\)的部分因为最多选 ...
- 【LOJ6089】小Y的背包计数问题(动态规划)
[LOJ6089]小Y的背包计数问题(动态规划) 题面 LOJ 题解 神仙题啊. 我们分开考虑不同的物品,按照编号与\(\sqrt n\)的关系分类. 第一类:\(i\le \sqrt n\) 即需要 ...
- LOJ6089 小Y的背包计数问题(根号优化背包)
Solutioon 这道题利用根号分治可以把复杂度降到n根号n级别. 我们发现当物品体积大与根号n时,就是一个完全背包,换句话说就是没有了个数限制. 进一步我们发现,这个背包最多只能放根号n个物品. ...
- LOJ6089 小Y的背包计数问题 背包、根号分治
题目传送门 题意:给出$N$表示背包容量,且会给出$N$种物品,第$i$个物品大小为$i$,数量也为$i$,求装满这个背包的方案数,对$23333333$取模.$N \leq 10^5$ $23333 ...
随机推荐
- POJ2259 Team Queue (JAVA)
第一次TLE,对每个group重新设置Queue中定位,定位到每个group的最后一个元素,但WA 经过检查,DEQUEUE时没有根据情况重新计算group,插入时没有根据情况重新给last赋值 贴A ...
- ubuntu下面的某些软件安装
1. python 下面的mysql驱动:不是在pip里面安装,执行下面命令 apt-get install python-mysqldb
- jquer 使用原生DOM对象
js中使document.getElementById("ID"); Jquery中可以使用$("#id") 或者$("#id").get( ...
- Python开发转盘小游戏
Python开发转盘小游戏 Python 一 原理分析 Python开发一个图形界面 有12个选项和2个功能键 确定每个按钮的位置 每个按钮的间隔相同 点击开始时转动,当前选项的背景颜色为红色,其他 ...
- P1001 A+B Problem (树链剖分)
这题考验我们构造模型的能力. 考虑构造一棵树,树上有3个节点,节点1和节点2连一条权值为a的边,节点1和节点3连一条权值为b的边,显然答案就是节点2到节点3的最短路径. 但这样还不够.考虑加法的性质, ...
- DFS-20190206
找出所有方案 排列和组合问题 排列: https://www.lintcode.com/problem/combination-sum/description public class Solutio ...
- Linux平台总线设备驱动
1. 平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其优势在于采用了总线的模型对设备(没有挂到真实总线的设备)与驱动进行了管理,这样提高了程序的可移植性. 2. 平台总 ...
- iview 怎样屏蔽掉账户框自动显示账户名和密码(root,***)
用iview框架做出的登录页面,账户名和密码显示框,会自动有占位信息(root,****) 后来解决问题发现,只要在真正的输入框下面添加这样的一行隐藏的代码,占位信息会自动填充到隐藏的input框内, ...
- 【OpenCV-Python】-图像平滑
原文为段立辉翻译,感谢Linux公社www.linuxidc.com此文档为自学转述,如有侵权请联系本人. 目标: • 学习使用不同的低通滤波器对图像进行模糊 • 使用自定义的滤波器对图像进行卷积(2 ...
- easyUI----纵向合并单元格
使用Easyui-DataGrid过程用.做统计/报表等时经常会使用到合并单元格,原生态Easyui-DataGrid没有合并单元格的属性或方法. 解决方案: 代码一 onLoadSuccess: f ...