40pts:
设f[i]表示现在在第i个柱子的最多果冻数。
考虑转移,那能转移过到i柱子的柱子一定是他与其之间距离绝对值小于等于m的,设它为k。
动态转移方程:
f
[
i
]
=
m
a
x
(
f
[
i
]
,
f
[
j
]
)
,
f
[
i
]
+
=
x
[
i
]
f[i]=max(f[i],f[j]),f[i]+=x[i]
f[i]=max(f[i],f[j]),f[i]+=x[i]
#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
const int N = 2e5 + 10;
int n, m, h[N], w[N], f[N], ans;
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d%d", &h[i], &w[i]);
for(int i=1;i<=n;i++)
{
for(int j=1;j<i;j++)
if(abs(h[i] - h[j]) <= m) f[i]=max(f[i],f[j]);
f[i]+=w[i];
}
for(int i = 1; i <= n; i++) ans = max(ans, f[i]);
printf("%d\n", ans);
return 0;
}
100pts:
设fi表示到了高度i能获得的最大果冻数
每做到一个木桩,判断能否更新f[hi]
即max{f[j]}+xi能否更优
j为转移状态,即高度[hi-m,hi+m]
其中能转移的最优状态设为f[k],则
f[hi] =max(f[hi],f[k]+xi)
这个状态可以用线段树在O(log2n)的时间内求出
总的时间复杂度是
O(n log2 max(hi))
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 2e6 + 10;
int n, m, ans, tmp, tree[N << 2], h[N], x[N];
int query(int now, int ql, int qr, int l, int r)
{
if(r < ql || l > qr) return 0;
if(ql <= l && r <= qr) return tree[now];
int mid = (l + r) >> 1;
return max(query(now << 1, ql, qr, l, mid) , query(now << 1 | 1, ql, qr, mid + 1, r));
}
void change(int now, int x, int val, int l, int r)
{
if(x == l && x == r) {tree[now] = val; retu rn;}
int mid = (l + r) >> 1;
if(x <= mid) change(now << 1, x, val, l, mid);
if(x > mid) change(now << 1 | 1, x, val, mid + 1, r);
tree[now] = max(tree[now << 1], tree[now << 1 | 1]);
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d%d", &h[i], &x[i]);
for(int i = 1; i <= n; i++)
{
tmp = query(1, max(h[i] - m, 0), h[i] + m, 1, 1000010) + x[i];
ans = max(ans , tmp);
change(1, h[i], tmp, 1, 1000010);
}
printf("%d\n", ans);
}