题解 [CF1458D] Flip and Reverse

传送门

这是真的神仙题!

  • 关于最小化字典序的另一种可能的切入点:转化为最小字典序欧拉路,用欧拉路满足限制,同时最小化字典序

发现这个操作十分神奇,完全不能找到性质
于是一个可能的切入点见Booksnow的题解

然后正解:
将 0 视为 -1,1 视为 1 后跑前缀和
则区间 01 数量相等的限制变为了 \(s_{l-1}=s_r\) 的限制
连边 \(s_i\to s_{i+1}\),那么发现一个合法区间一定形成一个环
发现对这个区间操作后相当于将这个环反着走一遍(这 tm 上哪发现去)
且对一个区间的操作并不改变这个区间形成的环上每种边的数量
所以可以直接建出图来跑字典序最小的欧拉路
对于本题,发现每个点的本质不同出边只有两种
所以可以贪心选字典序较小的边的条件是 没有字典序较大边 或 有从 \(now-1\) 回来的边
复杂度 \(O(n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 500010
#define ll long long
//#define int long long

int n;
char s[N];
int a[N], arr[N<<1][2];
int (*cnt)[2]=arr+N;

signed main()
{
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%s", s+1);
		n=strlen(s+1);
		for (int i=1; i<=n; ++i) a[i]=s[i]=='1'?1:-1;
		for (int i=1; i<=n; ++i) a[i]+=a[i-1];
		for (int i=-n; i<=n; ++i) cnt[i][0]=cnt[i][1]=0;
		for (int i=0; i<n; ++i) ++cnt[a[i]][s[i+1]-'0'];
		for (int i=1,now=0; i<=n; ++i) {
			if (cnt[now][0]&&(!cnt[now][1]||cnt[now-1][1])) --cnt[now][0], --now, putchar('0');
			else --cnt[now][1], ++now, putchar('1');
		}
		printf("\n");
	}

	return 0;
}
posted @ 2022-05-26 16:49  Administrator-09  阅读(3)  评论(0编辑  收藏  举报