Description
给出 n n 辆卡车,编号 1 1 ~ n n ,现在要从这些卡车中选出若干组成车队,以编号从小到大排,对于第 i i 辆卡车,其人数为 ci c i ,价值为 vi v i ,要求其前面卡车总人数为 li l i ,后面卡车总人数 ri r i ,问满足这些条件的车队总价值最大值
Input
第一行一整数 n n 表示车数量,之后 n n 行每行四个整数 vi,ci,li,ri(1≤n≤105,1≤vi≤104,1≤ci≤105,0≤li,ri≤105) v i , c i , l i , r i ( 1 ≤ n ≤ 10 5 , 1 ≤ v i ≤ 10 4 , 1 ≤ c i ≤ 10 5 , 0 ≤ l i , r i ≤ 10 5 )
Output
输出使得总价值最大的卡车数量和编号
Sample Input
5
1 1 0 3
1 1 1 2
1 1 2 1
1 1 3 0
2 1 3 0
Sample Output
4
1 2 3 5
Solution
对于被选的车,其前面车的总人数,后面车总人数加上这辆车的人数即所选车总人数,必然为定值,故把所有 li+ci+ri l i + c i + r i 值相同的车拿出来单独考虑,这样在转移过程中就不用考虑 ri r i 的限制了,以 dp[i] d p [ i ] 表示总人数为 i i 且所选的车满足条件时的最大价值,对于第 i i 辆车,如果存在 j j 满足 lj=li+ci l j = l i + c i ,那么有转移 dp[lj]=max(dp[lj],dp[li]+vi) d p [ l j ] = m a x ( d p [ l j ] , d p [ l i ] + v i ) ,只有 li=0 l i = 0 的车可以用来更新初值,只有 ri=0 r i = 0 的车可以用来更新答案,用 map m a p 存 dp d p 数组便于查询满足条件的后继
Code
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=100005;
int n,pre[maxn],s[maxn];
map<int,P>m;
P ans;
struct node
{
int v,c,l,r,id,sum;
bool operator<(const node &b)const
{
if(sum!=b.sum)return sumreturn idint main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&a[i].v,&a[i].c,&a[i].l,&a[i].r);
a[i].id=i;a[i].sum=a[i].c+a[i].l+a[i].r;
}
sort(a+1,a+n+1);
int res=0;
s[++res]=1;
ans.first=0;
for(int i=2;i<=n;i++)
{
if(a[i].sum==a[i-1].sum)s[++res]=i;
if(a[i].sum!=a[i-1].sum||i==n)
{
m.clear();
for(int j=1;j<=res;j++)
{
node t=a[s[j]];
if(t.l==0)
{
if(m.find(t.c)==m.end()||m[t.c].first0;
if(t.r==0&&m[t.c].first>ans.first)ans=m[t.c];
}
}
else
{
if(m.find(t.l)!=m.end())
{
if(m.find(t.l+t.c)==m.end()||m[t.l+t.c].firstif(t.r==0&&m[t.l].first+t.v>ans.first)
ans=P(m[t.l].first+t.v,t.id);
}
}
}
res=0;
s[++res]=i;
}
}
vector<int>vec;
int pos=ans.second;
while(pos)
{
vec.push_back(pos);
pos=pre[pos];
}
printf("%d\n",vec.size());
for(int i=vec.size()-1;i>=0;i--)printf("%d%c",vec[i],i?' ':'\n');
return 0;
}