构造,模拟,类别括号序列
题意
给定一些石头与一些目标位置,要求通过不超过 \(5n\) 次操作将所有石头移动到目标位置(目标位置不按顺序给出),定义操作如下:
- 选定两个石头,二者向二者中点的方向移动相同的距离。
给出构造,不要求最优。
\(1 \leq n \leq 3 \times 10^5\)
思路
显然可以将目标位置排序后与石头一一对应。
像维护括号序列一样,用栈维护目标位置与实际位置之差为负的位置,每遇到一个差是正数的就尝试用栈中的负数抵消(相当于一次操作)。
写题解时候感觉用队列也可以。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Maxn=3e5+10;
struct numb{int x,id;};
struct Ans{int i,j,d;};
numb t[Maxn];
int s[Maxn];
int n;
vector<Ans>ans;
bool cmp(numb x,numb y) {return x.x<y.x;}
signed main()
{cin>>n;for(int i=1;i<=n;i++) cin>>t[i].x,t[i].id=i;for(int i=1;i<=n;i++) cin>>s[i];sort(t+1,t+n+1,cmp);sort(s+1,s+n+1);stack<int>st;for(int i=1;i<=n;i++){t[i].x=s[i]-t[i].x;if(t[i].x>0) st.push(i);else if(t[i].x<0){while(t[i].x && st.size()){int tmp=min(-t[i].x,t[st.top()].x);ans.push_back((Ans){t[st.top()].id,t[i].id,tmp});t[i].x+=tmp; t[st.top()].x-=tmp;if(t[st.top()].x==0) st.pop();}if(t[i].x) return (cout<<"NO"<<endl,0);}}if(st.size()) return (cout<<"NO"<<endl,0);cout<<"YES"<<endl<<ans.size()<<endl;for(auto t:ans) cout<<t.i<<" "<<t.j<<" "<<t.d<<endl;return 0;
}