Liveddd's Blog

愛にできることはまだあるかい

CF1458D Flip and Reverse

巧妙的转化为欧拉路径。

0 视作 $-1$,将 1 视作 $+1$,转化为前缀和 $s_i$。操作 $[l,r]$ 的条件为 $s_{l-1}=s_r$。尝试研究操作的本质,容易发现就是对于 $[l-1,r]$ 的的前缀和的 reverse 操作。

对于前缀和 $s_i$ 对应的点建 $s_i\to s_{i+1}$ 这条边,而原字符串相当于一条欧拉路径。操作就相当于找到一个环,将上面的边反向。但实际上边集是不会变的,因为只有相邻的 $s_i$ 之间才会连边,所以环一定是若干个二元环拼起来的。更进一步的,我们发现,所有的可能的字符串,对应的图都是一样的,而图也对应所有可能的字符串。因为对于两条不同的欧拉路径,中间不同部分我们一定可以通过操作将其变为相同。所以问题转化为求字典序最小的欧拉路径。

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=5e5+10;
int T,n;
char s[N];
int e[N<<1][2];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%s",s+1);
n=strlen(s+1);
int x=N;
for(int i=1;i<=n;i++)
e[x][s[i]-'0']++,x+=(s[i]=='0'?-1:1);
x=N;
for(int i=1;i<=n;i++)
{
if(e[x][0]&&e[x-1][1])e[x][0]--,x--,putchar('0');
else if(e[x][1])e[x][1]--,x++,putchar('1');
else e[x][0]--,x--,putchar('0');
}
puts("");
}
return 0;
}