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 ...
随机推荐
- kafka-0.9
1)yum install java 2)curl -L -O http://mirrors.cnnic.cn/apache/kafka/0.9.0.0/kafka_2.10-0.9.0.0.tgz ...
- 安装php,nginx 带debug
gdb安装包 在CentOS6.4下使用gdb进行调试的时候, 使用bt(breaktrace)命令时,会弹出如下的提示: 头一天提示: Missing separate debuginfos, ...
- Orleans MultiClient 多个Silo复合客户端
目录 介绍 使用 简单例子 配置 注入到 DI 容器 添加多个 Client 全局 Orleans 服务配置 介绍 Orleans.MultiClient 是一个 Orleans 复合客户端,只需要简 ...
- leetcode-771-Jewels and Stones(建立哈希表,降低时间复杂度)
题目描述: You're given strings J representing the types of stones that are jewels, and S representing th ...
- 【http协议】浅谈
[http协议]浅谈 一. 概述 http,超文本传输协议(HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议. 请求与响应: 客户端发送请求,服务器端响应数 ...
- JQuery的get、post、ajax方法
1.jQuery $.get() 方法 $.get() 方法通过 HTTP GET 请求从服务器上请求数据. jQuery.get( url, [data], [callback] ): 参数: ...
- 【Python】子域名查询脚本
脚本学习,多写写就会啦,来一发个人编写的超级无敌low的子域名查询脚本 #coding:utf-8 import re import requests import urllib import url ...
- git设置core.autocrlf
背景: 使用虚拟机共享windows文件夹,文件夹中用git clone 一个仓库.在linux下编辑文件,用git status发现几乎所有的文件都为修改状态. 原因: windows下和lin ...
- init_config_file.lua
--[[ 读取限流配置 --]] --获取共享内存 local limit_req_store = ngx.shared.limit_req_store --初始化拒绝 URI 列表 reject_u ...
- 使用swiper来实现轮播图
使用swiper来实现轮播图 swiper实现轮播图几乎是没有一点点技术含量,但是用起来却很方便,包括对移动端的支持也很好. 由于简单这里当然就不会去详细介绍了,推荐两个网址: 1.http://ww ...