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 ...
随机推荐
- MACD 的数学解释
目录 MACD 的数学解释 MACD 的一般定义 引入延迟算子 Taylor 展开 权重分析 共振? MACD 的数学解释 MACD 的一般定义 \[ \begin{align*} DIF & ...
- django中多个app放入同一文件apps
新建一个apps文件夹 需要整理的app文件夹拖到同一个文件夹中,即apps.(弹出对话框,取消勾选Search for references) 在pycharm中,右键apps文件夹--选择mark ...
- origin显示三维曲面
准备数据并选中数据: 这里如果只关心z<1部分的趋势,可以对Z轴范围进行调整,双击Z轴的数字: 然后修改显色条的范围,双击曲面: 最后让曲面最上面部分clip掉: 成功了:
- [LnOI2019]加特林轮盘赌
Luogu5249 轮流开枪打一个环上的人 , 每次\(p\)的概率打死 , \(p\)始终相同 , 从第\(1\)个人开始 , 求第\(k\)个人成为唯一幸存者的概率 \(19.3.30\) 官方题 ...
- MVC返回数据流,ajax接受并保存文件
js代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <ti ...
- SqlServer索引优化 查看碎片情况
本文引自 DBCC DBREINDEX重建索引提高SQL Server性能 查看碎片情况使用 dbcc showcontig 函数来进行 代码: --改成当前库 use DB_Name --创建变量 ...
- ASP.NET实现数据绑定
一.数据绑定语法 数据绑定表达式包含在“<%#”和“%>”分隔符之内,并使用Eval方法和Bind方法.Eval方法用于定义单向(只读)绑定,Bind方法用于定义双向(可更新)绑定. 语法 ...
- db2 monitor event
1.创建事件监控器至少需要哪些权限? DBADM authority SQLADM authority 2.事件监控器的种类有哪些? 3. db2 flush event monitor eventm ...
- (转)MySQL 日志组提交
原文:https://jin-yang.github.io/post/mysql-group-commit.html 组提交 (group commit) 是为了优化写日志时的刷磁盘问题,从最初只支持 ...
- MySQL插入记录 insert
一.insert insert tb_name [(col_name,......)] {values | value} ({expr | default } ....... ) , ( ... ) ...