题解 CF1148E 【Earth Wind and Fire】

\[\huge\mathcal{Description} \]

日期 2020年8月24日
编号 \(\texttt{CF1148E}\)
算法 排序队列
来源 无名小题

\[\huge\mathcal{Solution} \]

这道题目,我们容易想到:排序后,石子的相对位置不会改变。
也就是说,将目标位置和起始位置分别排序后,\(Start_i\)一定对应\(End_i\)
然后,似乎变成了一道括号匹配问题
于是我们想到,所有石子所需的位移之和一定等于零,且每一段前缀和都不能小于零
无解判断完以后,我们使用类似于括号匹配问题的方法做即可。

\[\huge\mathcal{Code} \]

#include<bits/stdc++.h>
#define MAX 300001
using namespace std;
struct Struct
{
	int Position;
	int Id;
	inline bool operator < (const Struct &Compare)const
	{
		return Position<Compare.Position;
	}
};
struct Ans
{
	int PointA;
	int PointB;
	int Dist;
};
int TotalPoint;
Struct Start[MAX];
Struct End[MAX];
int Dist[MAX];
int main(void)
{
	register int i;
	cin>>TotalPoint;
	for(i=1;i<=TotalPoint;i++)
	{
		cin>>Start[i].Position;
		Start[i].Id=i;
	}
	for(i=1;i<=TotalPoint;i++)
	{
		cin>>End[i].Position;
		End[i].Id=i;
	}
	sort(Start+1,Start+TotalPoint+1);
	sort(End+1,End+TotalPoint+1);
	for(i=1;i<=TotalPoint;i++)
	{
		Dist[i]=End[i].Position-Start[i].Position;
	}
	register long long Sum;
	Sum=0;
	for(i=1;i<=TotalPoint;i++)
	{
		Sum+=Dist[i];
		if(Sum<0)
		{
			cout<<"NO"<<endl;
			return 0;
		}
	}
	if(Sum!=0)
	{
		cout<<"NO"<<endl;
		return 0;
	}
	register stack< int >Stack;
	register queue< Ans >Queue;
	for(i=1;i<=TotalPoint;i++)
	{
		if(!Dist[i])
		{
			continue;
		}
		if(Dist[i]>0)
		{
			Stack.push(i);
		}
		if(Dist[i]<0)
		{
			while(!Stack.empty())
			{
				register int Delta;
				register int j;
				j=Stack.top();
				Delta=min(Start[i].Position-End[i].Position,End[j].Position-Start[j].Position);
				Start[i].Position-=Delta;
				Start[j].Position+=Delta;
				Queue.push(Ans{Start[j].Id,Start[i].Id,Delta});
				if(Start[i].Position==End[i].Position)
				{
					break;
				}
				Stack.pop();
			}
		}
	}
	cout<<"YES"<<endl;
	cout<<Queue.size()<<endl;
	while(!Queue.empty())
	{
		cout<<Queue.front().PointA<<' '<<Queue.front().PointB<<' '<<Queue.front().Dist<<endl; 
		Queue.pop();
	}
	return 0;
}
posted @ 2020-08-24 13:19  Bushuai_Tang  阅读(168)  评论(0编辑  收藏  举报