题解 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;
}
不要妄图追上西坠的太阳,而是要在黎明前就等着它!