CF1394C 计算几何

题目大意:

n n n个字符串,每个字符串仅包含 B , N B,N BN两种字符,可以对 B N − s t r i n g BN-string BNstring进行如下操作:

  • 移走一个字符
  • 移走 “ 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. xx[i]+lxx[i]lyy[i]+lyy[i]lxyx[i]y[i]+lxyx[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 zminxyzmax,而 x − y x-y xy又有范围: 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 xminymaxxyxmaxymin,所以还要判断两个区间是否有交集

最后得到一个答案 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 zminxyzmax,所以 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+yminxzmax+ymax,而 x x x又有 x m i n ≤ x ≤ x m a x xmin \le x \le xmax xminxxmax,取交集中的一个数 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 zminxyzmax,所以 x 0 − z m a x ≤ y ≤ x 0 − z m i n x_0 - zmax \le y \le x0 - zmin x0zmaxyx0zmin,而 y y y又有 y m i n ≤ y ≤ y m a x ymin \le y \le ymax yminyymax,取交集即可

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值