巴里卡是一只不同寻常的青蛙

巴里卡是一只不同寻常的青蛙。她住在一个池塘里,有N株植物漂浮在水面上。植物编号为1到N。从上面看时,每个植物的位置由一对坐标给出。让巴里卡与众不同的是她害怕斜向和反向跳跃。更准确地说,她可以从坐标(x1,y1)处的一个植物跳到坐标(x2,y2)处的另一个植物,前提是:

•x2>x1,y2=y1

•y2>y1,x2=x1

对于每一种植物,我们知道其附近的苍蝇数量。巴里卡可以用她敏捷的舌头吃掉她所在植物附近的所有苍蝇。

巴里卡每吃一只苍蝇就吸收一个能量单位,每跳一次就消耗K个能量单位。如果事先没有足够的能量单位,巴里卡就跳不起来。

巴里卡希望从1号植物到N号植物,并在到达后尽可能获得最大的能量。巴里卡一开始没有能量,她必须从植物1周围的苍蝇那里收集能量进行第一次跳跃。

找到巴里卡为了实现目标应该旅行的植物序列。

输入格式:
第一行输入包含两个整数N和K(2≤N≤300000,1≤K≤1000)被一个空格隔开。
以下N行中的每一行都包含三个整数X、Y和F(0≤X、Y≤100000,0≤F≤1000)用空格隔开,这意味着在坐标(X,Y)处有一个植物,周围有F。

输入中的第一个植物是植物1,第二个是植物2等。
没有两个植物会共享同一对坐标。

注:输入数据将保证跳转序列始终存在,尽管不一定是唯一的。

输出格式:
在第一行输出最终的能级。
输出一个整数L,即巴里卡应该旅行的植物数量,包括植物1和N。
在下面的L行上,输出Barica应该移动的植物序列。

输入样例1:
6 5
1 1 5
2 1 5
1 2 4
2 3 5
3 2 30
3 3 5
输出样例1:
5
4
1 1
2 1
2 3
3 3
输入样例2:
8 10
1 1 15
2 2 30
1 2 8
2 1 7
3 2 8
2 3 7
4 2 100
3 3 15
输出样例2:
36
5
1 1
1 2
2 2
3 2
3 3
输入样例3:
9 5
5 5 10
6 5 2
7 5 1
5 6 2
6 6 6
7 6 2
5 7 1
6 7 2
7 7 1
输出样例3:
2
3
5 5
7 5
7 7

dp[i]表示跳到第i珠植物的最大能量
dpx[x]表示跳到植物坐标为x的最大能量
dpy[y]表示跳到植物坐标为y的最大能量
对输入的2~n-1进行排序以确保他是往后跳的,因为1和n不能动.
假设当前的坐标和价值为[x,y,w],dp转移为之前的dpx[x]跳到第i珠植物或者是dpy[y]跳到第i珠植物 dp[i]=max(dpx[x]-k+w,dpy[y]-k+w),同时保存一下路径。

//#pragma GCC optimize(2)
//#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
#define yes cout<<"Yes\n"
#define no cout<<"No\n"
#define yesno if(fg)yes;else no;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int inf=1e9;
const int maxn=3e5+100;
struct node
{
	int x,y,w;
} t[maxn];
int dp[maxn];
pii dpx[maxn],dpy[maxn];//first保存最大能量,second保存植物编号
int pre[maxn];
int cmp(node a,node b)
{
	if(a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
signed main()
{
	int n,k;
	cin>>n>>k;
	for(int i=1; i<=n; i++)
	{
		int x,y,w;
		cin>>x>>y>>w;
		t[i]= {x,y,w};
	}
	int idx=2;
//	for(int i=2;i<=n-1;i++)
//	{
//		if(t[i].x==t[1].x||t[i].y==t[1].y)
//		{
//			swap(t[i],t[idx]);
//			idx++;
//		}
//	}
	sort(t+idx,t+n,cmp);
//	cout<<"\n";
//	for(int i=1;i<=n;i++)
//	{
//		cout<<t[i].x<<" "<<t[i].y<<" "<<t[i].w<<"\n";
//	}
	dp[1]=t[1].w;
	dpx[t[1].x]= {t[1].w,1};
	dpy[t[1].y]= {t[1].w,1};
	for(int i=2; i<=n; i++)
	{
		auto [x,y,w]=t[i];
		if(x>t[n].x||y>t[n].y)continue;
		if(x<t[1].x||y<t[1].y)continue;
		if(dpx[x].fi>=k)
		{
			if(dpx[x].fi-k+w>dp[i])
			{
				dp[i]=dpx[x].fi-k+w;
				pre[i]=dpx[x].se;
			}
		}
		if(dpy[y].fi>=k)
		{
			if(dpy[y].fi-k+w>dp[i])
			{
				dp[i]=dpy[y].fi-k+w;
				pre[i]=dpy[y].se;
			}
		}
		if(dp[i]>dpx[x].fi)
		{
			dpx[x]= {dp[i],i};
		}
		if(dp[i]>dpy[y].fi)
		{
			dpy[y]= {dp[i],i};
		}
	}
	cout<<dp[n]<<"\n";
	vector<int>v;
	int now=n;
	while(now>=1)
	{
		v.pb(now);
		now=pre[now];
	}
	reverse(v.begin(),v.end());
	cout<<v.size()<<"\n";
	for(auto it:v)
	{
		cout<<t[it].x<<" "<<t[it].y<<"\n";
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

thusloop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值