51nod #13 D 【DP】【生成函数】
来源:互联网 发布:淘宝卖家客服人工服务 编辑:程序博客网 时间:2024/05/29 14:06
题目大意:有n种物品,第i种物品的大小为i,且有i个,求装满大小为n背包的方案数
贴题解:
首先我们可以发现,令
对于大小小于S的物品,我们可以令f[i][j]表示考虑了前i个物品,总大小为j的方案数,那么有:
我们在DP的时候,假设当前要计算f[i][j],可以设tmp[v]为当前满足t mod i=v的f[i-1][t]的和
然后就可以通过维护tmp数组,轻松计算出f[i][j]了
这一步的时间复杂度是
具体实现如下:
f[0][0]=1;for(int i=1;i<=S;i++){ for(int j=0;j<i;j++)tmp[j]=0; int nowmod=-1; //nowmod记录的是当前j mod i的值 for(int j=0;j<=n;j++){ nowmod++; if(nowmod>=i)nowmod=0; //维护nowmod tmp[nowmod]=tmp[nowmod]+f[i-1][j]; f[i][j]=tmp[nowmod]; //计算f[i][j],同时维护tmp if(j-i*i>=0)tmp[nowmod]=tmp[nowmod]-f[i-1][j-i*i]; //由于大小为i的只有i个,所以这里要减掉 }}
接下来考虑大小大于S的物品
我们考虑一个给物品“动态添加大小”的DP:
令g[i][j]表示,当前有i个物品,大小总和为j
我们可以做的转移是:
(1):将所有物品的大小加一 :g[i][j]->g[i][j+i]
(2):新建一个大小为S+1的物品g[i][j]->g[i+1][j+S+1]
可以发现,物品总数最多为n/S个,所有g的第一维的规模是n/S的,所以这一个DP也是O(n*sqrt(n))的
于是总复杂度就是O(n*sqrt(n))
这道题还有更加优美的算法,可以用多项式黑科技进行推导,可以得到复杂度O(nlogn)的做法,由于出题人能力有限所以这里就不阐述了
果然有O(nlogn)的做法,好厉害%%%
蒟蒻表示想了好久没有想出来诶。。。QAQ
最后窝只有用生成函数来水了一发。。。
我的做法:
同样是考虑
所以有
右边前面部分的分母是欧拉函数,有五边形数定理:
设
有
所以有
然后可以递推求得
答案
直接暴力乘起来就可以了
时间复杂度
#include<iostream>#include<algorithm>#include<cstdlib>#include<cstdio>#include<cstring>#include<string>#include<cmath>#include<ctime>#define N 100005#define M 23333333using namespace std;int n;int f[N];int main(){ scanf("%d",&n); f[0]=1; for (int i=1;i<=n;i++) for (int j=1;;j++) { int k=(3*j*j-j)>>1; if (k>i) break; if (~j&1) f[i]-=f[i-k]; else f[i]+=f[i-k]; if (f[i]>=M) f[i]-=M; if (f[i]<0) f[i]+=M; k+=j; if (k>i) break; if (~j&1) f[i]-=f[i-k]; else f[i]+=f[i-k]; if (f[i]>=M) f[i]-=M; if (f[i]<0) f[i]+=M; } int S=(int)sqrt(n); for (int i=1;i<=S;i++) { int k=i*i+i; for (int j=n;j>=k;j--) if ((f[j]-=f[j-k])<0) f[j]+=M; } cout<<f[n]<<endl; return 0;}
- 51nod #13 D 【DP】【生成函数】
- 51nod 1232 完美数 / codeforces 55D 数位DP
- 【DP or 生成函数】[CodeForces - 712D]Memory and Scores
- 51 nod D题
- 51nod 最长单增子序列 dp+(STL函数)二分
- 51nod 1371 DP
- 51NOD 1296-dp
- 51nod (dp)
- 51nod 1050【DP】
- 51nod 1268【dp】
- 51Nod - 1043 dp
- 51Nod - 1270 dp
- 51Nod - 1406 dp
- 51Nod - 1376 dp
- 51nod 1183 (dp)
- 【dp】51nod
- 51nod 1202 dp
- 51nod 1101 DP
- hdu 1069 Monkey and Banana
- Dubbo架构设计详解
- 设计模式C++学习笔记之十(Strategy策略模式)
- c语言特殊数之和
- c++ string类对象排序
- 51nod #13 D 【DP】【生成函数】
- XMG
- Mac os - idea 快捷键
- scala学习(4)——循环
- php命名空间里面的use关键字的理解
- uva 1424 (dp专组G题)
- This 指针
- 不同进制间的相互转换的理解
- 【EJB二】有状态SessionBean和无状态SessionBean