do_while_true

一言(ヒトコト)

「题解」Codeforces 1394C Boboniu and String

orz qyc

两个串相似实际上是两个字符串 'N' 和 'B' 的数量一致。

\(s_i\)\(x_i\) 个 'N',\(y_i\) 个 'B',\(t\)\(x\) 个 'N',\(y\) 个 'B'。

分类讨论一下 \(dist(s,t)\)\(x,x_i\) 以及 \(y,y_i\) 大小关系不同的四种情况下的取值。

发现四种情况分别为:

\(x-y-x_i+y_i,-(x-y)+x_i-y_i,\max(x_i-x,y_i-y),\max(x-x_i,y-y_i)\)

对出现的六个式子求 \(\max\) 恰好为答案,具体为何同样可以分类讨论四种情况。

二分答案转判定,就变成要求 \(\max\) 里面六个值都 \(\geq mid\)

发现实际上是对 \(x,y,x-y\) 的取值范围作出限制。

后面就很简单了,算出各自的取值范围,然后看前两项不等式的差出来的范围是否和后一项的范围有交即可,构造方案枚举个 \(x\) 随便怎么构造都可。

其实分类讨论有很多细节,但是这里仅给出主要思路不商讨细节部分。

//Code by do_while_true
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
typedef long long ll;
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template <typename T> T Abs(T x) { return x < 0 ? -x : x; }
template <typename T> T chkmax(T &x, T y) { return x = x > y ? x : y; }
template <typename T>
T &read(T &r) {
	r = 0; bool w = 0; char ch = getchar();
	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
	while(ch >= '0' && ch <= '9') r = (r << 3) + (r <<1) + (ch ^ 48), ch = getchar();
	return r = w ? -r : r;
}
const int N = 300010;
const int INF = 100000000;
int n, a[N], b[N];
//a:N  b:B
char ch[N];
bool check(int x) {
	int l1, r1, l2, r2, l3, r3;
	l1 = -INF, r1 = INF; l2 = 0, r2 = INF; l3 = 0; r3 = INF;
	for(int i = 1; i <= n; ++i) {
		l1 = Max(l1, a[i]-b[i]-x);
		r1 = Min(r1, a[i]-b[i]+x);
		l2 = Max(l2, a[i]-x);
		r2 = Min(r2, a[i]+x);
		l3 = Max(l3, b[i]-x);
		r3 = Min(r3, b[i]+x);
	}
	if(l2 < 0 || l3 < 0) return 0;
	if(l1 > r1 || l2 > r2 || l3 > r3) return 0;
	int l4 = l2 - r3, r4 = r2 - l3;
	return r1 >= l4 && l1 <= r4;
}
signed main() { //freopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);
	read(n);
	if(n == 1) {
		scanf("%s", ch+1);
		puts("0");
		printf("%s\n", ch+1);
		return 0;
	}
	for(int i = 1; i <= n; ++i) {
		scanf("%s", ch+1);
		int len = std::strlen(ch+1);
		for(int j = 1; j <= len; ++j)
			if(ch[j] == 'N') ++a[i];
			else ++b[i];
	}
	int l = 0, r = INF, mid, ans = 0;
	while(l <= r) {
		mid = (l + r) >> 1;
		if(check(mid)) ans = mid, r = mid-1;
		else l = mid+1;
	}
	printf("%d\n", ans);
	int l1, r1, l2, r2, l3, r3;
	l1 = -INF, r1 = INF; l2 = 0, r2 = INF; l3 = 0; r3 = INF;
	for(int i = 1; i <= n; ++i) {
		l1 = Max(l1, a[i]-b[i]-ans);
		r1 = Min(r1, a[i]-b[i]+ans);
		l2 = Max(l2, a[i]-ans);
		r2 = Min(r2, a[i]+ans);
		l3 = Max(l3, b[i]-ans);
		r3 = Min(r3, b[i]+ans);
	}
	int l4 = l2 - r3, r4 = r2 - l3;
	l = Max(l1, l4); r = Min(r1, r4);
	for(int i = l2; i <= r2; ++i) {
		int _l = i - r3, _r = i - l3;
		if(Max(_l, l) <= Min(r, _r)) {
			int p = Max(_l, l);
			if(i || (i-p)) {
				for(int j = 1; j <= i-p; ++j) printf("B");
				for(int j = 1; j <= i; ++j) printf("N");
				return 0;
			}
			else {
				p = Min(r, _r);
				if(i || (i-p)) {
					for(int j = 1; j <= i-p; ++j) printf("B");
					for(int j = 1; j <= i; ++j) printf("N");
					return 0;
				}
			}
		}
	}
	return 0;
}
posted @ 2021-07-23 10:57  do_while_true  阅读(45)  评论(0编辑  收藏  举报