CF28D Don‘t fear, DravDe is kind

一、题目

点此看题

二、解法

首先 l + c + r l+c+r 相同的分到一组,最优解一定只能出现在某一组内,每一组内单独做 d p dp ,设 d p [ i ] dp[i] 为前面包括自己的人数和为 i i 的最大权值,每次只需要更新一次,所以时间复杂度是 O ( n ) O(n) 的,转移:
d p [ l + c ] = d p [ l ] + v dp[l+c]=dp[l]+v 最后找出最优的那一组,再跑一遍还原路径即可。

#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int M = 300005;
const int inf = 0x3f3f3f3f;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,mx,cur,dp[M],fa[M],k[M],ans[M];
struct node
{
	int v,c,l,r,id;
};vector<node> a[M];
void print(int x)
{
	if(x==-1) return ;
	print(fa[x]);
	printf("%d ",a[cur][x].id);
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++)
	{
		int v=read(),c=read(),l=read(),r=read();
		a[l+c+r].push_back(node{v,c,l,r,i});
	}
	memset(dp,-0x3f,sizeof dp);
	dp[0]=0;
	for(int i=1;i<=300000;i++)
	{
		for(int j=0;j<a[i].size();j++)
			dp[a[i][j].c+a[i][j].l]=max(dp[a[i][j].c+a[i][j].l],dp[a[i][j].l]+a[i][j].v);
		if(dp[i]>mx)
		{
			mx=dp[i];
			cur=i;
		}
		for(int j=0;j<a[i].size();j++)
			dp[a[i][j].c+a[i][j].l]=-inf;
	}
	memset(k,-1,sizeof k);
	memset(fa,-1,sizeof fa);
	for(int i=cur,j=0;j<a[i].size();j++)
	{
		if(dp[a[i][j].c+a[i][j].l]<dp[a[i][j].l]+a[i][j].v)
		{
			dp[a[i][j].c+a[i][j].l]=dp[a[i][j].l]+a[i][j].v;
			fa[j]=k[a[i][j].l];
			k[a[i][j].c+a[i][j].l]=j;
			ans[a[i][j].c+a[i][j].l]=ans[a[i][j].l]+1;
		}
	}
	printf("%d\n",ans[cur]);
	print(k[cur]);
}

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/107926856
今日推荐