51nod1597 有限背包计数问题
来源:互联网 发布:js事件的onfocus 编辑:程序博客网 时间:2024/06/03 17:58
基准时间限制:2.333 秒 空间限制:131072 KB 分值: 160 难度:6级算法题
你有一个大小为n的背包,你有n种物品,第i种物品的大小为i,且有i个,求装满这个背包的方案数有多少
两种方案不同当且仅当存在至少一个数i满足第i种物品使用的数量不同
Input
第一行一个正整数n 1<=n<=10^5
Output
一个非负整数表示答案,你需要将答案对23333333取模
Input示例
3
Output示例
2
题外话:我喜欢这道题的时间限制和模数。这道题我感觉非常好(也可能是因为我太弱了)。时间效率光荣垫底了(所以建议大家不要看我的代码,请只看分析吧)。
作为蒟蒻我只可以想到没有限制时的
我们不妨分成两部分考虑:设
首先是前
再来看第二部分的计算,什么?你想用完全背包?算一下时间复杂度吧。这里我们就要用到一种比较神奇的思想了——序列思想(澄清一下:出题人解题报告里称其为“给物品动态添加大小的
撒花庆祝,剩下的我们只需要统计一下总方案数就好了,乘法原理:
#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;typedef long long ll;const int N=100010;const int M=320;const ll mod=23333333LL;int n,m,f[2][N],g[M][N],tmp[N];int now,pre=1;ll f1[N],g1[N],ans;int main(){ scanf("%d",&n);f[0][0]=g[0][0]=1; m=(int)ceil(sqrt((double)n)); for (int i=1;i<=m;++i) { for (int j=0;j<i;++j)tmp[j]=0; int nowmod=-1;swap(now,pre); for (int j=0;j<=n;++j) { ++nowmod;if(nowmod>=i)nowmod=0; (tmp[nowmod]+=f[pre][j])%=mod; f[now][j]=tmp[nowmod]; if(j>=i*i) tmp[nowmod]=(tmp[nowmod]-f[pre][j-i*i]+mod)%mod; } } for (int i=0;i<=m;++i) { for (int j=0;j<=n;++j) { if(i&&j+i<=n)(g[i][j+i]+=g[i][j])%=mod; if(j+m+1<=n)(g[i+1][j+m+1]+=g[i][j])%=mod; } } ++g1[0]; for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) (g1[i]+=g[j][i])%=mod; for (int i=0;i<=n;++i)f1[i]=f[now][i]; for (int i=0;i<=n;++i) (ans+=(f1[i]*g1[n-i]%mod))%=mod; printf("%I64d\n",ans); return 0;}
其它比我厉害多了的做法:ORZ r_64的母函数解法
ORZ tangjz的五边形数解法(咦,好像也是母函数吧,只不过是从系数以及函数的角度考虑的):
关于五边形数定理:参考文章1、参考文章2、参考文章3
对于这道题我们先求出没有限制时的分割数,然后再化一下式子(公式恐惧症又犯了),如果只有
#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;const int N=100100;const int mod=23333333;int T,n,K,ans[N];#define f(x) (((x)*(3*(x)-1))>>1)#define g(x) (((x)*(3*(x)+1))>>1)#define h(x) ((x)*((x)+1))int main(){ scanf("%d",&n);ans[0]=1; for (int i=1;i<=n;++i) { for (int j=1;f(j)<=i;++j) if(j&1) ans[i]=(ans[i]+ans[i-f(j)])%mod; else ans[i]=(ans[i]-ans[i-f(j)]+mod)%mod; for (int j=1;g(j)<=i;++j) if(j&1) ans[i]=(ans[i]+ans[i-g(j)])%mod; else ans[i]=(ans[i]-ans[i-g(j)]+mod)%mod; } for (int i=1;h(i)<=n;++i) for (int j=n;j>=h(i);--j) ans[j]=(ans[j]-ans[j-h(i)]+mod)%mod; printf("%d\n",ans[n]); return 0;}
总结:
1、仔细且耐心分析题目中限制性条件的诸多性质,例如其影响、贡献、被限制的条件、与没有限制的不同(比如考虑放松限制然后计数原理等)。
2、考虑分块、分治等方法处理问题(比如把定义域、值域分为不同的两部分,分别处理,还有经典的meet in the middle),往往能简化时间、空间复杂度。
3、序列思想很值得推广,体现了一种动态修改的思想,修改的时间不同,得到的结果也不同,对于能简化为一个序列、多项式等模型貌似都可以使用。
- 51nod1597 有限背包计数问题
- 【51nod1597】【DP】有限背包计数问题
- [51nod1597] 有限背包计数问题
- 【阈值优化+背包】51Nod1597[有限背包计数问题]题解
- 51nod1597 有限背包计数问题[DP][分类讨论][前缀和]
- 有限背包计数问题
- 51nod 1597 有限背包计数问题
- 51Nod-1597-有限背包计数问题
- 1597 有限背包计数问题
- [背包DP || 多项式] 51Nod 1597 有限背包计数问题
- 【背包+阈值优化】51Nod 1597 有限背包计数问题
- 51nod 1597 有限背包计数问题 dp
- [DP] 51Nod 1597 有限背包计数问题
- [DP]51 Nod 1597——有限背包计数问题
- 51nod 1597 有限背包计数问题[dp][阈值]
- 有限背包计数问题 (分类dp)
- [背包DP][小技巧] LOJ#6089. 小 Y 的背包计数问题 && 51NOD 1597 有限背包计数问题
- 51nod 1201[整数划分] 1259[整数划分V2] 1597 [有限背包计数问题]
- JS产生随机数的几个用法!
- 数据结构[刷水]
- rocksdb:DestroyDB函数
- 创建真机和模拟器都能使用的静态库.a文件
- ACM专题三1012
- 51nod1597 有限背包计数问题
- sql2000/sql2005/sql2008数据库变为0字节修复/MDF文件0字节恢复
- SpringMVC接收参数中文乱码问题
- HLS协议之服务器与客户端之前的交互流程
- Android - ImageButton单击切换按钮图片效果的实现
- java反射
- 【Linux】U盘挂载与取消挂载
- Cesium 如何获得高度
- Oracle dataguard一主两备环境搭建