CF1458D Flip and Reverse

一个\(01\)串,可以如此操作:选择一个\(0,1\)出现次数相同的子串,将其翻转并取反。

问经过任意次操作之后的字典序最小的字符串是什么。

\(n\le 5*10^5\)


神仙转化。

\(0\)视作\(+1\),把\(1\)视作\(-1\),做个前缀和\(s_i\)。连边\((s_i,s_{i+1})\)

原来的字符串相当于这个图上的一条欧拉路径。

思考下一个操作意味着什么:相当于找到欧拉路径上的一个环,将其反向并翻转。

然后可以发现任意两个合法的欧拉路径可以通过这个操作转化,也就是:任意合法的欧拉路径都是能够形成的字符串。

然后就是个图上找最小字典序欧拉路径的问题。

两种做法:经典做法,直接递归做,回溯的时候把点丢入栈中,最后倒序输出栈中的点,做之前把边从小到大排序;或者也可以直接贪心选,但是要保证现在走的这条边不是桥。由于这题的特殊性,这个东西是比较好判断的。


using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 500005
int n;
char s[N];
int _e[N+N];
#define e(x) (_e[(x)+N])
int q[N],k;
void dfs(int x){
	while (e(x)){
		e(x)--;
		dfs(x+1);
	}
	while (e(x-1)){
		e(x-1)--;
		dfs(x-1);
	}
	q[++k]=x;
}
int main(){
	freopen("in.txt","r",stdin);
	int T;
	scanf("%d",&T);
	while (T--){
		scanf("%s",s+1);
		n=strlen(s+1);
		int x=0;
		for (int i=1;i<=n;++i){
			int y=x+(s[i]=='0'?1:-1);			
			e(min(x,y))++;
			x=y;			
		}
		dfs(0);
		x=0;
		for (--k;k;--k){
			int y=q[k];
			if (x+1==y)
				putchar('0');
			else
				putchar('1');
			x=y;
		}
		putchar('\n');
	}
	return 0;
}
posted @ 2020-12-20 15:30  jz_597  阅读(302)  评论(0编辑  收藏  举报