Description
给出nn辆卡车,编号~nn,现在要从这些卡车中选出若干组成车队,以编号从小到大排,对于第辆卡车,其人数为cici,价值为vivi,要求其前面卡车总人数为lili,后面卡车总人数riri,问满足这些条件的车队总价值最大值
Input
第一行一整数nn表示车数量,之后行每行四个整数vi,ci,li,ri(1≤n≤105,1≤vi≤104,1≤ci≤105,0≤li,ri≤105)vi,ci,li,ri(1≤n≤105,1≤vi≤104,1≤ci≤105,0≤li,ri≤105)
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+rili+ci+ri值相同的车拿出来单独考虑,这样在转移过程中就不用考虑riri的限制了,以dp[i]dp[i]表示总人数为ii且所选的车满足条件时的最大价值,对于第辆车,如果存在jj满足,那么有转移dp[lj]=max(dp[lj],dp[li]+vi)dp[lj]=max(dp[lj],dp[li]+vi),只有li=0li=0的车可以用来更新初值,只有ri=0ri=0的车可以用来更新答案,用mapmap存dpdp数组便于查询满足条件的后继
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
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 sum<b.sum;
return id<b.id;
}
}a[maxn];
int 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].first<t.v)
{
m[t.c]=P(t.v,t.id);
pre[t.id]=0;
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].first<m[t.l].first+t.v)
{
m[t.l+t.c]=P(m[t.l].first+t.v,t.id);
pre[t.id]=m[t.l].second;
}
if(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;
}