AtCoder Beginner Contest 465 C - Reverse Permutation 题解

貌似好像只有我是这么写的。

思路

我们发现序列中的每一个数都有一个前驱和后继,当序列颠倒时只需修改对应的数的前驱后继即可,修改规则如下:

  • 从前向后遍历字符串,并设反转后的序列开头为 \(h\),开始时 \(h=1\)
  • \(i\) 位为x,不修改。
  • \(i\) 位为o,将 \(i+1\) 的前驱改为 \(h\)\(h\) 的后继改为 \(h\) 的前驱。

然后你就会发现当你改完后 \(1\)\(i\) 之间的数的前驱后继并没有改,它爆掉了......
不用慌,既然前驱后继改不了,那我们就不分前驱和后继了,那么我们应该改称为
由于一个点只有两条边,可以快速添加和删除,整个程序复杂度为 \(O(n)\)
至于输出,由于已经知道 \(h\),每个节点只有一个出边和入边,遍历输出就行。
用图表示就是:
无标题
无标题1

代码

#include<bits/stdc++.h>
using namespace std;
const int NUM=5e5+10;

int n;
string s;
int e[NUM][2];
void addedge(int x,int y){
	if(!e[x][0]) e[x][0]=y;
	else e[x][1]=y;
}
void deledge(int x,int y){
	if(e[x][0]==y) e[x][0]=0;
	else e[x][1]=0;
}

signed main(){
	cin>>n>>s;s=' '+s;
	for(int i=1;i<=n;++i){
		addedge(i,i+1);
		addedge(i,i-1);
	}
	int h=1;
	for(int i=1;i<=n;++i){
		if(s[i]=='o'){
			deledge(h,0);
			deledge(i,i+1);
			addedge(h,i+1);
			addedge(i+1,h);
			h=i;
		}
	}
	bitset<NUM> vis;
	while(h&&h<=n){
		cout<<h<<' ';
		vis[h]=1;
		if(!vis[e[h][0]]&&e[h][0]) h=e[h][0];
		else h=e[h][1];
	}
	return 0;
}

sbmqwm的双指针扫描做法

posted @ 2026-07-04 21:49  LZYXT  阅读(19)  评论(2)    收藏  举报