传送门

dp好题。

我认为原题的描述已经很清楚了:

你有一个大小为n的背包,你有n种物品,第i种物品的大小为i,且有i个,求装满这个背包的方案数有多少。

两种方案不同当且仅当存在至少一个数i满足第i种物品使用的数量不同。


然而我只会O(n2)O(n^2)O(n2)的做法。

然后通过搜题解学会了O(n∗sqrt(n))O(n*sqrt(n))O(n∗sqrt(n))的做法。

简单讲讲。

首先我们需要分布考虑。

对于大于sqrt(n)sqrt(n)sqrt(n)的物品是选不完的,相当于没有数量限制。

而小于sqrt(n)sqrt(n)sqrt(n)的物品是有数量限制的。

但是直接上多重背包效率上天。

因此我们开始考虑如何优化。

先想想dp式子。

f[i][j]=∑f[i−1][j−k∗i]f[i][j]=\sum f[i-1][j-k*i]f[i][j]=∑f[i−1][j−k∗i]

这启发我们按照余数分组维护f[i−1][jf[i-1][jf[i−1][j modmodmod i]i]i]的前缀和来进行优化。

这样前半部分效率是O(n∗sqrt(n))O(n*sqrt(n))O(n∗sqrt(n))的。

继续考虑后半部分如何维护。

后半部分是一个特殊的完全背包问题。

我们可以想象把所有物品都放在序列上。

那么现在有两种更新方式。

  1. 我们把所有物品向后移一个位置
  2. 在队首插入一个最小的数sqrt(n)+1sqrt(n)+1sqrt(n)+1

这就是一种动态转移的思想,这个方法的正确性在于这两种更新方式能够考虑到当前维护所有的序列状态并借此转移出后面的状态。

只是妙不可言。

代码:

#include<bits/stdc++.h>
#define N 100005
#define mod 23333333
#define ll long long
using namespace std;
int n,m,tmp,f[2][N],g[320][N],sum[N];
ll sumg[N],ans=0;
int main(){
	scanf("%d",&n),m=sqrt(n),f[0][0]=g[0][0]=sumg[0]=1;
	for(int i=1;i<=m;++i){
		memset(sum,0,sizeof(sum));
		int mod_cnt=-1;
		tmp^=1;
		for(int j=0;j<=n;++j){
			++mod_cnt;
			if(mod_cnt==i)mod_cnt=0;
			f[tmp][j]=((sum[mod_cnt]+=f[tmp^1][j])%=mod);
			if(j>=i*i)(sum[mod_cnt]+=mod-f[tmp^1][j-i*i])%=mod;
		}
	}
	for(int i=0;i<=m;++i)
		for(int j=0;j<=n;++j){
			if(i&&i+j<=n)(g[i][i+j]+=g[i][j])%=mod;
			if(j+m+1<=n)(g[i+1][j+m+1]+=g[i][j])%=mod;
		}
	for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)(sumg[i]+=g[j][i])%=mod;
	for(int i=0;i<=n;++i)(ans+=1ll*f[tmp][i]*sumg[n-i]%mod)%=mod;
	cout<<ans;
	return 0;
}

2018.09.25 51nod1597 有限背包计数问题(背包+前缀和优化)的更多相关文章

  1. LOJ6089 小Y的背包计数问题 背包、根号分治

    题目传送门 题意:给出$N$表示背包容量,且会给出$N$种物品,第$i$个物品大小为$i$,数量也为$i$,求装满这个背包的方案数,对$23333333$取模.$N \leq 10^5$ $23333 ...

  2. 2018.09.08 bzoj1531: [POI2005]Bank notes(二进制拆分优化背包)

    传送门 显然不能直接写多重背包. 这题可以用二进制拆分/单调队列优化(感觉二进制好写). 所谓二进制优化,就是把1~c[i]拆分成20,21,...2t,c[i]−2t+1+1" role= ...

  3. 51nod 1597 有限背包计数问题 (背包 分块)

    题意 题目链接 Sol 不会做啊AAA.. 暴力上肯定是不行的,考虑根号分组 设\(m = \sqrt{n}\) 对于前\(m\)个直接暴力,利用单调队列优化多重背包的思想,按\(\% i\)分组一下 ...

  4. LOJ6089 小Y的背包计数问题 背包

    正解:背包 解题报告: 先放传送门! 好烦昂感觉真的欠下一堆,,,高级数据结构知识点什么的都不会,基础又麻油打扎实NOIp前的题单什么的都还麻油刷完,,,就很难过,,,哭辣QAQ 不说辣看这题QwQ! ...

  5. 2018.09.25 poj2068 Nim(博弈论+dp)

    传送门 题意简述:m个石子,有两个队每队n个人循环取,每个人每次取石子有数量限制,取最后一块的输,问先手能否获胜. 博弈论+dp. 我们令f[i][j]f[i][j]f[i][j]表示当前第i个人取石 ...

  6. 2018.09.25 bzoj1856: [Scoi2010]字符串(组合数学)

    传送门 如果有n==m的条件就是卡特兰数. 但现在n不一定等于m. 我们可以考虑用求卡特兰数一样的方法来求答案. 我们知道有一种求卡特兰数的方法是转到二维平面求答案. 这道题就可以这样做. 我们将这个 ...

  7. 2018.09.25 bzoj2286: [Sdoi2011]消耗战(虚树+树形dp)

    传送门 又一道虚树入门题. 这个dp更简单啊. 直接记录每个点到1的距离,简单转移就行了. 代码: #include<bits/stdc++.h> #define N 250005 #de ...

  8. 2018.09.25 bzoj3572: [Hnoi2014]世界树(虚树+树形dp)

    传送门 虚树入门题? 好难啊. 在学习别人的写法之后终于过了. 这道题dp方程很好想. 主要是不好写. 简要说说思路吧. 显然最优值只能够从子树和父亲转移过来. 于是我们先dfs一遍用儿子更新父亲,然 ...

  9. 2018.09.25 codeforces1053E. Euler tour(并查集+st表+模拟)

    传送门 毒瘤细节题. 首先考虑不合法的情况. 先把相同的值配对,这样就构成了一些区间. 那么如果这些区间有相交的话,就不合法了. 如何判断?DZYO安利了一波st表,我觉得很不错. 接着考虑两个相同的 ...

随机推荐

  1. linux 关于数据库的部分命令

    开启数据库服务 service mysqld start 关闭数据库服务 service mysqld stop 链接数据库 mysql -h localhost -u root -p 回车然后输入密 ...

  2. 17 网络编程 C/S架构介绍

    1.什么是C/S架构 C指的是client(客户端软件),S指的是Server(服务器软件),本章的重点是教大家写一个C/S架构的软件,实现服务端软件与客户端软件基于网络通信. 2.计算机基础的知识- ...

  3. 15 python re 模块

    1.基础知识 正则表达式是用于处理字符串的强大工具,拥有自己独特的语法以及一个独立的处理引擎 正则表达式的大致匹配流程:依次拿出表达式和文本中的字符比较, 如果每一个字符都能匹配,则匹配成功:一旦有匹 ...

  4. ABAP-关于隐式与显式的DB Commit

    转载:https://www.cnblogs.com/liaojunbo/archive/2011/07/11/2103491.html 1.显式的DB Commit 显式的DB Commit并没有对 ...

  5. 修改thinkpad 小红点(TrackPoint速度)

    from: http://www.jianshu.com/p/b9677e9e56ec Thinkpad大概是对Linux支持最好的笔记本了,Ubuntu大概是对硬件支持最好的Linux发行版了.Ub ...

  6. Kafka Manager 监控

    1.安装: 依赖java环境,须首先安装java运行环境,并正确设置路径. 确保kafka已经安装,且版本合适. 修改配置文件:   kafka-manager.zkhosts="你的zoo ...

  7. pyorient

    简介 pyorient是orientdb的python库 该库提供两种访问orientdb的方式:1.client 的方式 2.ogm 的方式(类似于ORM) 由于OGM 封装了client,且由于O ...

  8. 吴裕雄 python 数据处理(1)

    import time print(time.time())print(time.localtime())print(time.strftime('%Y-%m-%d %X',time.localtim ...

  9. Python基础语法题库

    引言: 语法练习包括Python基础语法.数据类型.字符编码和简单文件操作等内容. 正文(参考答案附录在题目下方): 1.Python 里用来告知解释器跳过当前循环中的剩余语句,然后继续进行下一轮循环 ...

  10. python,遍历文件的方法

    在做验证码识别时,识别时需要和库里的图片对比,找到最接近的那个图片,然后就行到了用与图片一致的字符命名,获取文件的名称,去将图片的名称读出来作为验证码.以下是我通过网上的资料总结的三种文件遍历的方式, ...