「解题报告」CF1444D Rectangular Polyline

这类型的题我们可以先找一些显然的必要条件,然后再去构造,很有可能就发现它是充分条件。

考虑有什么必要条件:首先 \(n=m\),要不然无法横纵首尾相连。

其次所有横必定能划分成两个和相等的集合,纵一样。

那么我们首先跑个背包将横纵划分成两个集合,这样我们相当于有了若干向量,我们要将它们连成一个多边形。

考虑先将一个横向量和一个纵向量合成为一个斜向量。那么我们得到了 \(n\) 个斜向量。按照极角排序首尾相连,我们便能得到一个凸多边形。

image

但是问题是,虽然这个凸多边形两两不交,但是形成的多边形可能有交。

image

那怎么办呢?我们发现,能够发生相交的向量只有二三象限(或一四象限)。假如我们让这其中一个象限没有向量,就一定不会有交了。

事实上,当我们将横向量和纵向量相加的时候,只需要先对横纵向量进行排序,就只会得到三个象限的向量。

这个很容易发现,不举例子了。

那么我们只需要先排序,结合起来,再按照极角排序,输出答案即可。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int T;
int n, m;
int a[MAXN], b[MAXN];
bitset<2 * MAXN * MAXN> f[MAXN];
pair<int, int> c[MAXN];
bool operator<(pair<int, int> a, pair<int, int> b) {
    return atan2(a.second, a.first) < atan2(b.second, b.first);
}
int main() {
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        scanf("%d", &m);
        for (int i = 1; i <= m; i++) {
            scanf("%d", &b[i]);
        }
        if (n != m) {
            printf("No\n");
            continue;
        }
        {
            for (int i = 0; i <= n; i++) {
                f[i].reset();
            }
            f[0][MAXN * MAXN] = 1;
            for (int i = 1; i <= n; i++)
                f[i] = (f[i - 1] << a[i]) | (f[i - 1] >> a[i]);
            if (!f[n][MAXN * MAXN]) {
                printf("No\n");
                continue;
            }
            int s = MAXN * MAXN;
            for (int i = n; i >= 1; i--) {
                if (f[i - 1][s + a[i]]) {
                    s += a[i];
                    a[i] *= -1;
                } else {
                    s -= a[i];
                }
            }
        }
        {
            for (int i = 0; i <= n; i++) {
                f[i].reset();
            }
            f[0][MAXN * MAXN] = 1;
            for (int i = 1; i <= n; i++)
                f[i] = (f[i - 1] << b[i]) | (f[i - 1] >> b[i]);
            if (!f[n][MAXN * MAXN]) {
                printf("No\n");
                continue;
            }
            int s = MAXN * MAXN;
            for (int i = n; i >= 1; i--) {
                if (f[i - 1][s + b[i]]) {
                    s += b[i];
                    b[i] *= -1;
                } else {
                    s -= b[i];
                }
            }
        }
        sort(a + 1, a + 1 + n);
        sort(b + 1, b + 1 + n, greater<>());
        printf("Yes\n");
        for (int i = 1; i <= n; i++) {
            c[i] = { a[i], b[i] };
        }
        sort(c + 1, c + 1 + n);
        int x = 0, y = 0;
        for (int i = 1; i <= n; i++) {
            printf("%d %d\n", x, y);
            y += c[i].second;
            printf("%d %d\n", x, y);
            x += c[i].first;
        }
    }
    return 0;
}
posted @ 2023-03-11 16:43  APJifengc  阅读(22)  评论(0编辑  收藏  举报