[bzoj2131] 免费的馅饼
Description
Input
第一行是用空格隔开的二个正整数,分别给出了舞台的宽度W(1到10^8之间)和馅饼的个数n(1到10^5)。 接下来n行,每一行给出了一块馅饼的信息。由三个正整数组成,分别表示了每个馅饼落到舞台上的时刻t[i](1到10^8秒),掉到舞台上的格子的编号p[i](1和w之间),以及分值v[i](1到1000之间)。游戏开始时刻为0。输入文件中同一行相邻两项之间用一个空格隔开。输入数据中可能存在两个馅饼的t[i]和p[i]都一样。
Output
一个数,表示游戏者获得的最大总得分。
Sample Input
3 4
1 2 3
5 2 3
6 3 4
1 1 5
1 2 3
5 2 3
6 3 4
1 1 5
Sample Output
12
【数据规模】
对于100%的数据,1<=w,t[i]<=10^8,1<=n<=100000。
【数据规模】
对于100%的数据,1<=w,t[i]<=10^8,1<=n<=100000。
这道题真的令我印象十分特别深刻...。 在东北的时候听过 回来又听zyl讲过
这道题是一道用线段树解决的二位偏序的$dp$问题
dp[i]表示当前吃第$i$块馅饼所能够获得的最大价值 考虑如何转移 转移方程式是很简单的
$dp[i] = max(dp[j] + val[i])$,$j$属于能够转移到$i$的馅饼
那么现在需要解决的问题就是哪些馅饼能够转移到$i$号 首先$j$号馅饼一定要在$i$号馅饼之前出现
考虑如果$j$号馅饼能够转移到$i$号 那么还需要满足式子
$|pos[i] - pos[j]| <= 2 * (t[i] - t[j])$
打开绝对值之后得到的两个化简得到两个关于$i,j$的式子 将同属性的移到等式一边得到
$2 * t[i] - pos[i] >= 2 * t[j] - pos[j] , 2 * t[i] + pos[i] >= 2 * t[j] + pos[j]$
发现这两个式子是等价的 也就是说只要同时满足上面两个式子 原始式子就一定成立
证明:
$1.pos[i] >= pos[j]$ 也就是说他满足了式子$1$ 原本$t[i] > t[j]$ 那么$2 * t[i]$加上$pos[i]$后会比左边更大 一定成立
第二种情况的证明是一样的 所以两只需要同时满足这两个属性就可以进行转移
代码
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5; int n,m,tt[N],f[4 * N],w,dp[N]; struct food { int f1,f2,val; }b[N]; void init( ) { int t,p,val; scanf("%d%d",& w,& n); for(int i = 1;i <= n;i ++) { scanf("%d%d%d",& t,& p,& val); b[i].f1 = 2 * t + p; b[i].f2 = 2 * t - p; b[i].val = val; tt[i] = 2 * t + p; } sort(tt + 1,tt + n + 1); m = unique(tt + 1,tt + n + 1) - tt - 1; } void update(int o) { f[o] = max(f[2 * o],f[2 * o + 1]); } bool cmp(const food & a,const food & b) { return a.f2 < b.f2; } int query(int o,int l,int r,int L,int R) { if(l >= L && r <= R) return f[o]; int mid = (l + r) >> 1; int ans = 0; if(L <= mid) ans = max(ans,query(2 * o,l,mid,L,R)); if(mid < R) ans = max(ans,query(2 * o + 1,mid + 1,r,L,R)); return ans; } void modify(int o,int l,int r,int pos,int val) { if(l == r) { f[o] = max(f[o],val); return ; } int mid = (l + r) >> 1; if(pos <= mid) modify(2 * o,l,mid,pos,val); else modify(2 * o + 1,mid + 1,r,pos,val); update(o); } int main( ) { init( ); sort(b + 1,b + n + 1,cmp); for(int i = 1;i <= n;i ++) { int pos = lower_bound(tt + 1,tt + m + 1,b[i].f1) - tt; int q = query(1,1,m,1,pos); dp[i] = q + b[i].val; modify(1,1,m,pos,dp[i]); } printf("%d",query(1,1,m,1,m)); return 0; }