codeforces 480D

时间:2023-03-09 05:30:09
codeforces 480D

题意:给定一些物品放置在承重为S的桌子上, 每个物品有5个属性,放置时间in,拿开时间out,重量w,承重s及放置后的收益v。而且后面放置上去的必须先拿开。。求一种合法的放置使得收益最大,输出收益。

思路:先对所有的物品按照out递增,out相同l递减的情况排序。

那么很容易想到dp。。

f[i][j]表示放置了第i个,还可承重j的最大收益(i本身还没算)。

把(in[i], out[i])看成线段

那么,等价于(in[i], out[i])之间找出最多不相交线段。

这个可以用记忆化搜索,当然也可以非递归。。

具体看代码应该比较容易懂吧。。
code:

 #include <bits/stdc++.h>
using namespace std;
struct oo{
int l, r, w, s, v;
void input(){
scanf("%d%d%d%d%d", &l, &r, &w, &s, &v);
}
bool operator<(const oo& p) const{
return r < p.r || (r == p.r && l > p.l);
}
} a[];
int n, s, f[][], tmp[];
void solve(){
a[] = (oo){, n*, , s, };
for (int i = ; i <= n; ++i) a[i].input();
sort(a, a + n + );
int cur, s1;
for (int i = ; i <= n; ++i)
for (int j = a[i].w; j <= s; ++j){
tmp[cur = a[i].l] = ;
s1 = min(j-a[i].w, a[i].s);
for (int k = ; k < i; ++k) if (a[k].l >= a[i].l){
for (;cur<a[k].r;)
++cur, tmp[cur] = tmp[cur-];
tmp[cur] = max(tmp[cur], tmp[a[k].l] + f[k][s1]);
}
f[i][j] = tmp[cur] + a[i].v;
}
cout << f[n][s] << endl;
} int main(){
// freopen("a.in", "r", stdin);
while (scanf("%d%d", &n, &s) != EOF){
solve();
}
}