【学习笔记】「JOISC 2020 Day1」汉堡肉

solution:

考点:数学 + 2-sat 模型。

观察 k ≤ 4 k\leq 4 k4 肯定有猫腻。

设所有正方形的右边界最小值为 m n x mnx mnx

则可以证明若有解一定存在一个竹签使得其纵坐标为 m n x mnx mnx ,即调整坐标得到不劣的方案。

类似的也有同样的性质。对于 k ≤ 3 k\leq 3 k3 的情况,根据鸽巢原理,一定存在一个竹签落在四个角上。直接 O ( 4 k n ) O(4^kn) O(4kn) 爆搜即可。

对于 k = 4 k=4 k=4 的情况,正确考虑方式为:如果一个矩形如果和三条直线相交,那么一定包含一条边界,可以不用考虑;否则考虑 2-sat 模型。限制条件为:若两个区间不存在交,则一定不能被同一条边覆盖。

那我们可以把 l, r 端点分别 push_back 进每一个可能满足的边,对于每个 l, 向满足 r<l 的点建边,同理,对于每个 r,向满足 l>r 的点建边。可以 two-pointers 完成。这样要构造 2*3=6 倍节点。

时间复杂度 O ( n ( l o g n + 4 k ) ) O(n(logn+4^k)) O(n(logn+4k)) 。代码好恶心。

代码是 z y y zyy zyy 的,做了一些改动。 d e b u g debug debug 了一晚上终于改对了代码。

#include <bits/stdc++.h> #define PII pair<int,int> #define INF 0x3f3f3f3f #define ll long long #define fi first #define se second #define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++) #define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--) using namespace std; const int mx = 2e5 + 5; const int mxn = mx * 6; int n, k, nd, cnt[mx], id[mx][2], pr[mx], su[mx], at[mx][2]; int dfn[mxn], low[mxn], vis[mxn], c[mxn], s[mxn], tp, bl, num; struct qry { int x, v0, v1; bool operator <(const qry &a) const { return x < a.x; } }; vector<qry> vl[4], vr[4]; vector<int> g[mxn]; PII ans[5]; struct node { int x, y, x2, y2; } a[mx]; void add(int x, int y) { if (!x || !y) return; g[x].push_back(y); } void change(int x, int y, int r) { for (int i = 1; i <= n; i++) { if (a[i].x <= x && x <= a[i].x2 && a[i].y <= y && y <= a[i].y2) { cnt[i] += r; } } } void dfs(int d) { int mnx = 1e9, mxx = 1; int mny = 1e9, mxy = 1; for (int i = 1; i <= n; i++) { if (!cnt[i]) { mnx = min(mnx, a[i].x2); mxx = max(mxx, a[i].x); mny = min(mny, a[i].y2); mxy = max(mxy, a[i].y); } } if (d == 1) { if (mxx <= mnx && mxy <= mny) { printf("%d %d\n", mnx, mny); for (int i = 2; i <= k; i++) { printf("%d %d\n", ans[i].fi, ans[i].se); } exit(0); } return; } int a[2] = {mnx, mxx}, b[2] = {mny, mxy}; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { ans[d] = make_pair(a[i], b[j]); change(a[i], b[j], 1), dfs(d - 1), change(a[i], b[j], -1); } } } void tarjan(int x) { dfn[x] = low[x] = ++num, vis[x] = 1, s[++tp] = x; for (auto y : g[x]) { if (!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]); else if (vis[y]) low[x] = min(low[x], dfn[y]); } if (low[x] == dfn[x]) { int tmp(0); bl++; do { tmp = s[tp--]; c[tmp] = bl; vis[tmp] = 0; } while (tmp != x); } } int main() { // freopen("test.in","r",stdin); // freopen("own.out","w",stdout); scanf("%d%d", &n, &k); for (int i = 1; i <= n; i++) { scanf("%d%d%d%d", &a[i].x, &a[i].y, &a[i].x2, &a[i].y2); } dfs(k); int mnx = 1e9, mxx = 1; int mny = 1e9, mxy = 1; For(i, 1, n) { mnx = min(mnx, a[i].x2); mxx = max(mxx, a[i].x); mny = min(mny, a[i].y2); mxy = max(mxy, a[i].y); } if (mnx > mxx) swap(mnx, mxx); if (mny > mxy) swap(mny, mxy); For(i, 1, n) { a[i].x = max(a[i].x, mnx); a[i].x2 = min(a[i].x2, mxx); a[i].y = max(a[i].y, mny); a[i].y2 = min(a[i].y2, mxy); } for (int i = 1; i <= n; i++) { int fl = 0, s = 0, d = 0; if (a[i].x <= mnx && mnx <= a[i].x2) fl |= 1, s++; if (a[i].x <= mxx && mxx <= a[i].x2) fl |= 2, s++; if (a[i].y <= mny && mny <= a[i].y2) fl |= 4, s++; if (a[i].y <= mxy && mxy <= a[i].y2) fl |= 8, s++; if (s >= 3) continue; if (s == 0) return 0; id[i][0] = ++nd; id[i][1] = ++nd; if (s == 1) g[nd].push_back(nd - 1); for (int j = 0; j <= 3; j++) { if (fl >> j & 1) { at[i][d] = j; if (j & 2) { vl[j].push_back({a[i].x, id[i][d], id[i][d ^ 1]}); vr[j].push_back({a[i].x2, id[i][d], id[i][d ^ 1]}); d++; } else { vl[j].push_back({a[i].y, id[i][d], id[i][d ^ 1]}); vr[j].push_back({a[i].y2, id[i][d], id[i][d ^ 1]}); d++; } } } } for (int i = 0; i <= 3; i++) { if (!vl[i].size()) continue; int sz = vl[i].size(), pos = 0; sort(vl[i].begin(), vl[i].end()); sort(vr[i].begin(), vr[i].end()); pr[0] = su[sz + 1] = 0; for (int j = 1; j <= sz; j++) { pr[j] = ++nd; add(pr[j], pr[j - 1]); add(pr[j], vr[i][j - 1].v1); } for (int j = sz; j >= 1; j--) { su[j] = ++nd; add(su[j], su[j + 1]); add(su[j], vl[i][j - 1].v1); } for (int j = 0; j < sz; j++) { for (; pos < sz && vl[i][j].x > vr[i][pos].x; pos++); add(vl[i][j].v0, pr[pos]); } pos = 0; for (int j = 0; j < sz; j++) { for (; pos < sz && vr[i][j].x >= vl[i][pos].x; pos++); add(vr[i][j].v0, su[pos + 1]); } } for (int i = 1; i <= nd; i++) { if (!dfn[i]) tarjan(i); } for (int i = 1; i <= n; i++) { if (id[i][0] && c[id[i][0]] == c[id[i][1]]) { printf("-1"); return 0; } } int mn[4], mx[4]; For(i, 0, 3) { mn[i] = (i & 2 ? mnx : mny); mx[i] = (i & 2 ? mxx : mxy); } For(i, 1, n) if (id[i][0]) { int flg = (c[id[i][0]] > c[id[i][1]]); int idd = at[i][flg]; mn[idd] = max(mn[idd], (idd & 2 ? a[i].x : a[i].y)); mx[idd] = max(mx[idd], (idd & 2 ? a[i].x2 : a[i].y2)); } printf("%d %d\n", mnx, mn[0]); printf("%d %d\n", mxx, mn[1]); printf("%d %d\n", mn[2], mny); printf("%d %d\n", mn[3], mxy); }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530270.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(8)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示