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;
}