[bzoj2131] 免费的馅饼
2017-10-25 20:38
190 查看
题目大意
你在一个1*W的格子图上,最开始可以在任意位置。每一个时刻你可以向左右移动1或2格,也可以不动。第i个馅饼在ti时刻落在位置pi上,价值为vi。问你可以获得的最大价值和是多少。n≤100000 W,pi,ti≤108
分析
设f[i]表示最后一个拿到的馅饼是i的答案。i能转移到j,需要满足的条件是|wi−wj|≤2(tj−ti)
可以把绝对值拆开,变成wi−wj≤2(tj−ti)且wj−wi≤2(tj−ti)。这样是等价的。
移项变成2ti+wi≤2tj+wj和2ti−wi≤2tj−wj,那么可以按其中一个的升序顺序枚举,并离散化另一个,用树状数组维护前缀最大值来做。
O(nlogn)
#include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <set> #define max(a,b) ((a)>(b)?(a):(b)) using namespace std; const int N=1e5+5; typedef long long LL; int W,n,m,g ,f ,ans; set <int> t; map <int,int> id; struct Data { int t,p,v; }A ; bool operator < (Data a,Data b) { return a.t*2-a.p<b.t*2-b.p; } void Add(int x,int y) { for (;x<=n;x+=x&-x) g[x]=max(g[x],y); } int getmax(int x) { int k=0; for (;x>0;x-=x&-x) k=max(k,g[x]); return k; } int main() { scanf("%d%d",&W,&n); for (int i=1;i<=n;i++) { scanf("%d%d%d",&A[i].t,&A[i].p,&A[i].v); t.insert(A[i].t*2+A[i].p); } sort(A+1,A+n+1); for (set <int> ::iterator it=t.begin();it!=t.end();it++) id[*it]=++m; for (int i=1;i<=n;i++) { ans=max(ans,f[i]=getmax(id[A[i].t*2+A[i].p])+A[i].v); Add(id[A[i].t*2+A[i].p],f[i]); } printf("%d\n",ans); return 0; }
相关文章推荐
- bzoj 2131: 免费的馅饼(树状数组+DP)
- [BZOJ2131]免费的馅饼-树状数组优化DP
- 【BZOJ2131】免费的馅饼,坐标转换与DP
- bzoj2131: 免费的馅饼
- [BZOJ]2131 免费的馅饼 DP + 绝对值转化
- 【bzoj2131】免费的馅饼 dp+树状数组
- [BZOJ2131]免费的馅饼(DP+树状数组)
- [BZOJ]2131: 免费的馅饼 DP+树状数组
- [bzoj2131]免费的馅饼_树状数组
- bzoj 2131: 免费的馅饼【dp+树状数组】
- BZOJ P2131 免费的馅饼
- hdu 1176 免费馅饼 dp
- 免费馅饼
- hdoj--1176--免费馅饼(动态规划)
- 【COGS272】【NOI1998】免费馅饼(dp)
- hdu1176 免费馅饼
- hdu 1176免费馅饼 2151 Worm
- 1176-免费馅饼
- HDU - 1176 免费馅饼 (简单DP)
- HDU-1176-数塔DP-免费馅饼