题目大意:
n n n个字符串,每个字符串仅包含 B , N B,N B,N两种字符,可以对 B N − s t r i n g BN-string BN−string进行如下操作:
- 移走一个字符
- 移走 “ B N ” “BN” “BN”, “ N B ” “NB” “NB”的子串
- 添加一个字符 B B B,或 N N N在 s s s的末尾
- 添加 “ B N ” “BN” “BN”或者 “ N B ” “NB” “NB”在 s s s的末尾
定义两个字符串相似的条件: B B B与 N N N的个数分别都相等
且定义 d i s t ( s , t ) dist(s,t) dist(s,t)代表 s s s与 t t t相似的最小操作次数
找到一个字符串 t t t,使得 m a x i = 1 n d i s t ( s i , t ) max_{i=1}^{n}dist(s_i,t) maxi=1ndist(si,t)最小
解题思路:(思路来源:WYXkk)
首先队对以上的操作进行分析:
- 假设字符串 t t t的 B B B, N N N都大于 s s s,那么此时最好先对 t t t进行第二种操作,再执行第一种操作,而第二种操作必须是子串,所以我们可以将 t t t变成类似形式: B . . . B N . . . N B...BN...N B...BN...N
- 假设字符串 t t t的 B B B, N N N都小于 s s s,那么此时先对 t t t执行第四种操作,再执行第三种操作
- 最后这种情况,就是分别执行第一种,第三种操作即可
通过以上分析,操作可以变成如下:
- 移走一个字符或添加一个字符
- 添加/删除一个 B B B以及一个 N N N
对于最大值最小这类问题,一般都是二分答案,那么现在就是如何检验
假设二分的答案是 l l l
- 可以将每个字符串的 B B B的个数以及 N N N的个数,分别当作横纵坐标画在坐标轴上
那么每个点移动的方向就如下:
最后范围就是:
所以只要对所有点这样的图形判断是否有交集即可
- 对于这种非常规则的图形,很多可以不用半平面交来判断
先写出方程:
{
x
≤
x
[
i
]
+
l
x
≥
x
[
i
]
−
l
y
≤
y
[
i
]
+
l
y
≥
y
[
i
]
−
l
x
−
y
≤
x
[
i
]
−
y
[
i
]
+
l
x
−
y
≥
x
[
i
]
−
y
[
i
]
−
l
\left\{\begin{matrix} x \le x[i] + l \\ x \ge x[i]-l \\ y \le y[i] + l \\ y \ge y[i] - l \\ x - y \le x[i] - y[i] + l \\ x - y \ge x[i] - y[i] - l \end{matrix}\right.
⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧x≤x[i]+lx≥x[i]−ly≤y[i]+ly≥y[i]−lx−y≤x[i]−y[i]+lx−y≥x[i]−y[i]−l
- 对于以上方程分别对每个范围的最小值取 m a x max max,以及最大值取 m i n min min
判断是否图形有交集:( x m i n xmin xmin为 x x x的最小范围,其余同理,设 z m i n zmin zmin为斜的最小距离)
-
x m i n > x m a x xmin > xmax xmin>xmax 或者 y m i n > y m a x ymin > ymax ymin>ymax 或者 z m i n > z m a x zmin > zmax zmin>zmax即交集为空
-
因为 z m i n ≤ x − y ≤ z m a x zmin \le x-y\le zmax zmin≤x−y≤zmax,而 x − y x-y x−y又有范围: x m i n − y m a x ≤ x − y ≤ x m a x − y m i n xmin - ymax \le x-y\le xmax - ymin xmin−ymax≤x−y≤xmax−ymin,所以还要判断两个区间是否有交集
最后得到一个答案 l l l,还要找出有多少个 B B B以及 N N N
- 因为 z m i n ≤ x − y ≤ z m a x zmin \le x - y \le zmax zmin≤x−y≤zmax,所以 z m i n + y m i n ≤ x ≤ z m a x + y m a x zmin + ymin \le x \le zmax + ymax zmin+ymin≤x≤zmax+ymax,而 x x x又有 x m i n ≤ x ≤ x m a x xmin \le x \le xmax xmin≤x≤xmax,取交集中的一个数 x 0 x_0 x0就好
- 已知 x 0 x_0 x0以及 z m i n ≤ x − y ≤ z m a x zmin \le x - y \le zmax zmin≤x−y≤zmax,所以 x 0 − z m a x ≤ y ≤ x 0 − z m i n x_0 - zmax \le y \le x0 - zmin x0−zmax≤y≤x0−zmin,而 y y y又有 y m i n ≤ y ≤ y m a x ymin \le y \le ymax ymin≤y≤ymax,取交集即可
AC代码:
#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) //不能跟puts混用
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 5e5 + 10;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
int n, x[maxn], y[maxn];
bool check(int l) {
int xmin = -inf, xmax = inf, ymin = -inf, ymax = inf, zmin = -inf, zmax = inf;
for (int i = 1; i <= n; i++) {
xmin = max(xmin, x[i] - l);
xmax = min(xmax, x[i] + l);
ymin = max(ymin, y[i] - l);
ymax = min(ymax, y[i] + l);
zmin = max(zmin, x[i] - y[i] - l);
zmax = min(zmax, x[i] - y[i] + l);
}
xmin = max(xmin, 0); ymin = max(ymin, 0);
if (xmin > xmax || ymin > ymax || zmin > zmax) return 0;
int zzmin = xmin - ymax, zzmax = xmax - ymin;
if (zzmax < zmin || zmax < zzmin) return 0;
return 1;
}
int main() {
cin >> n;
string s;
for (int i = 1; i <= n; i++) {
cin >> s;
for (int j = 0; j < s.size(); j++)
(s[j] == 'B') ? x[i]++ : y[i]++;
}
int lc = 0, rc = 1e6, mc, res;
while (lc <= rc) {
mc = (lc + rc) >> 1;
if (check(mc)) rc = mc - 1, res = mc;
else lc = mc + 1;
}
cout << res << endl;
int xmin = -inf, xmax = inf, ymin = -inf, ymax = inf, zmin = -inf, zmax = inf;
for (int i = 1; i <= n; i++) {
xmin = max(xmin, x[i] - res);
xmax = min(xmax, x[i] + res);
ymin = max(ymin, y[i] - res);
ymax = min(ymax, y[i] + res);
zmin = max(zmin, x[i] - y[i] - res);
zmax = min(zmax, x[i] - y[i] + res);
}
int x0 = min(xmax, zmax + ymax), y0 = min(x0 - zmin, ymax);
for (int i = 1; i <= x0 + y0; i++)
if (i <= x0) cout << 'B';
else cout << 'N';
cout << endl;
return 0;
}