Day1T1 建筑装饰4

题目链接:Day1T1 建筑装饰4

Solution

我们先考虑朴素的\(dp\)方法:

设\(dp_{i,j,k}\)表示前\(i\)个数中,选了\(j\)个\(B\)数组中的数,并且第\(i\)个数选的是\(A/B\)时,是否存在满足单调不降的数列。

复杂度:\(O(n^2)\),期望得分:\(11\)分。

考虑如何优化。可以打个表,发现当\(i,k\)固定的时候,满足\(dp_{i,j,k}=1\)的\(j\)刚好是一个区间。

我们可以大胆猜结论:如果\(dp_{i,j_1,k}=1\)并且\(dp_{i,j_2,k}=1\),那么对于任意\(j_1\le j\le j_2\),都满足\(dp_{i,j,k}=1\)。

于是,我们可以记录数组\(l_{i,k}\)和\(r_{i,k}\)分别表示最小的\(j\)和最大的\(j\)。

输出路径的时候从后往前找即可。

复杂度:\(O(n)\),期望得分:\(100\)分。

Code

// Author: wlzhouzhuan
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std; #define ll long long
#define ull unsigned long long
#define rint register int
#define rep(i, l, r) for (rint i = l; i <= r; i++)
#define per(i, l, r) for (rint i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define mp(a, b) make_pair(a, b) inline int read() {
int x = 0, neg = 1; char op = getchar();
while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
return neg * x;
}
inline void print(int x) {
if (x < 0) { putchar('-'); x = -x; }
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
} const int inf = 1e9;
const int N = 1000005;
int l[N][2], r[N][2];
int a[N][2], n; void ckmin(int &a, int b) {
if (a > b) a = b;
}
void ckmax(int &a, int b) {
if (a < b) a = b;
} int main() {
// freopen("building.in", "r", stdin);
// freopen("building.out", "w", stdout); n = read();
a[0][0] = a[0][1] = -inf, a[2 * n + 1][0] = a[2 * n + 1][1] = inf;
for (rint i = 1; i <= 2 * n; i++) a[i][0] = read();
for (rint i = 1; i <= 2 * n; i++) a[i][1] = read();
for (rint i = 1; i <= 2 * n; i++) {
for (rint j = 0; j <= 1; j++) {
l[i][j] = inf, r[i][j] = -inf;
for (rint k = 0; k <= 1; k++) {
if (a[i][j] >= a[i - 1][k]) {
ckmin(l[i][j], l[i - 1][k] + (j == 0));
ckmax(r[i][j], r[i - 1][k] + (j == 0));
}
}
}
}
stack <int> ans;
if (l[2 * n][0] <= n && n <= r[2 * n][0]) {
int lef = n, st = 0;
ans.push(0);
for (rint i = 2 * n - 1; i >= 1; i--) {
if (st == 0) {
lef--;
for (rint j = 0; j <= 1; j++) {
if (a[i + 1][st] >= a[i][j] && l[i][j] <= lef && lef <= r[i][j]) {
st = j;
break;
}
}
} else {
for (rint j = 0; j <= 1; j++) {
if (a[i + 1][st] >= a[i][j] && l[i][j] <= lef && lef <= r[i][j]) {
st = j;
break;
}
}
}
ans.push(st);
}
while (!ans.empty()) {
if (ans.top() == 0) putchar('A');
else putchar('B');
ans.pop();
}
puts("");
} else if (l[2 * n][1] <= n && n <= r[2 * n][1]) {
int lef = n, st = 1;
ans.push(1);
for (rint i = 2 * n - 1; i >= 1; i--) {
if (st == 0) {
lef--;
for (rint j = 0; j <= 1; j++) {
if (a[i + 1][st] >= a[i][j] && l[i][j] <= lef && lef <= r[i][j]) {
st = j;
break;
}
}
} else {
for (rint j = 0; j <= 1; j++) {
if (a[i + 1][st] >= a[i][j] && l[i][j] <= lef && lef <= r[i][j]) {
st = j;
break;
}
}
}
ans.push(st);
}
while (!ans.empty()) {
if (ans.top() == 0) putchar('A');
else putchar('B');
ans.pop();
}
puts("");
} else {
puts("-1");
}
return 0;
}

Day1T2 汉堡肉

题目链接:Day1T2 汉堡肉

Solution

对于\(k=1\),显然这个点位于这\(n\)个矩形的交。

复杂度:\(O(n)\),期望得分:\(2\)分。

对于\(k=2\),令\(r=min_{i=1}^{n}R_i\),令其中一个点的横坐标为\(r\),同时枚举它所有的可能纵坐标,并且包含这个点的矩形删掉。

剩余的矩形按\(k=1\)的做法即可得到另一个点。

复杂度:\(O(n^2)\),期望得分:\(1\)分,结合\(k=1\)可得\(3\)分。

考虑如何优化。我们先将所有的矩形按照\(R_i\)优化,然后在扫描线的过程中记录剩余矩形中的\(max(L_i),max(D_i),min(R_i),min(U_i)\)。

具体过程可以用优先队列来实现。

复杂度:\(O(nlogn)\),期望得分:\(3\)分,结合\(k=1\)可得\(6\)分。

对于剩下的点,我采用了随机化做法。

先随机打乱这\(n\)个矩形,然后将前\(k\)个矩形分别放置这\(k\)类。

接下来,将第\(k+1到n\)这些矩形依次插入这\(k\)类。

定义估价函数\(h(rec_x,rec_y)=\frac{area(merge(rec_x,rec_y))}{area(rec_y)}\)表示覆盖率。

我们可以去寻找第\(i\)个矩形与第\(j\)类矩阵交后的估价函数最大值。

那么估价函数越高,即越优秀,匹配成功的概率最大。

按照如上方式随机化,可以通过此题。

复杂度:\(O(欧皇)\),期望得分:\(100\)分。

Code

// Author: wlzhouzhuan
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std; #define ll long long
#define ull unsigned long long
#define rint register int
#define rep(i, l, r) for (rint i = l; i <= r; i++)
#define per(i, l, r) for (rint i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define mp(a, b) make_pair(a, b) inline int read() {
int x = 0, neg = 1; char op = getchar();
while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
return neg * x;
}
inline void print(int x) {
if (x < 0) { putchar('-'); x = -x; }
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
} const int N = 200005;
int n, k;
struct rect {
ll x1, y1, x2, y2;
rect(ll _x1 = 0, ll _y1 = 0, ll _x2 = 0, ll _y2 = 0) {
x1 = _x1, y1 = _y1, x2 = _x2, y2 = _y2;
}
} a[N], b[5]; rect merge(rect x, rect y) {
return rect(max(x.x1, y.x1), max(x.y1, y.y1), min(x.x2, y.x2), min(x.y2, y.y2));
}
ll area(rect x) { // 矩形内包含多少点
if (x.x1 > x.x2 || x.y1 > x.y2) return 0;
else return (x.x2 - x.x1 + 1) * (x.y2 - x.y1 + 1);
} double h(rect x, rect y) {
rect m = merge(x, y);
return area(m) / 1.0 / area(y);
} int main() {
srand(time(NULL));
scanf("%d%d", &n, &k);
for (rint i = 1; i <= n; i++) {
scanf("%lld%lld%lld%lld", &a[i].x1, &a[i].y1, &a[i].x2, &a[i].y2);
}
while (true) {
int ok = 1;
random_shuffle(a + 1, a + n + 1);
for (rint i = 1; i <= k; i++) b[i] = a[i];
for (rint i = k + 1; i <= n; i++) {
double max_h = -1e9; int id = 1;
for (rint j = 1; j <= k; j++) {
double _h = h(a[i], b[j]);
if (_h > max_h) {
max_h = _h;
id = j;
}
}
b[id] = merge(b[id], a[i]);
if (area(b[id]) <= 0) {
ok = 0;
break;
}
}
if (ok) break;
}
for (rint i = 1; i <= k; i++) {
printf("%lld %lld\n", b[i].x1, b[i].y1);
}
return 0;
}

谈谈正经的做法

// Author: wlzhouzhuan
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std; #define ll long long
#define ull unsigned long long
#define rint register int
#define rep(i, l, r) for (rint i = l; i <= r; i++)
#define per(i, l, r) for (rint i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define mp(a, b) make_pair(a, b)
#define all(x) x.begin(), x.end() inline int read() {
int x = 0, neg = 1; char op = getchar();
while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
return neg * x;
}
inline void print(int x) {
if (x < 0) { putchar('-'); x = -x; }
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
} inline void ckmin(int &a, int b) {
if (a > b) a = b;
}
inline void ckmax(int &a, int b) {
if (a < b) a = b;
} const int N = 1500005;
const int inf = 1e9; struct rect {
int x1, y1, x2, y2;
} a[N];
int n, K; pair <int, int> ans[5];
int cnt[N];
void modify(int x, int y, int v) {
for (rint i = 1; i <= n; i++) {
if (a[i].x1 <= x && x <= a[i].x2 && a[i].y1 <= y && y <= a[i].y2) {
cnt[i] += v;
}
}
}
void dfs(int d) {
int x1 = -inf, x2 = inf, y1 = -inf, y2 = inf;
for (rint i = 1; i <= n; i++) if (!cnt[i]) {
ckmax(x1, a[i].x1), ckmax(y1, a[i].y1);
ckmin(x2, a[i].x2), ckmin(y2, a[i].y2);
}
if (d == 1) {
if (x1 <= x2 && y1 <= y2) { // 最后一个点在剩余矩形的交内
ans[1] = make_pair(x1, y1);
for (rint i = 1; i <= K; i++) {
printf("%d %d\n", ans[i].first, ans[i].second);
}
exit(0);
}
return ;
}
for (rint cx = 0; cx < 2; cx++) {
for (rint cy = 0; cy < 2; cy++) {
int px = (cx ? x1 : x2);
int py = (cy ? y1 : y2);
modify(px, py, 1);
ans[d] = make_pair(px, py);
dfs(d - 1);
modify(px, py, -1);
}
}
} vector <int> h[N];
vector <tuple <int, int, int>> sl[4], sr[4];
int pre[4][N], suf[4][N], id[N][4]; int fir(tuple <int, int, int> a) {
return get<0>(a);
}
int sec(tuple <int, int, int> b) {
return get<1>(b);
}
int thi(tuple <int, int, int> c) {
return get<2>(c);
} vector <int> G[N];
void add(int u, int v) { G[u].push_back(v); }
int dfn[N], low[N], dtot;
int ins[N], be[N], scc;
stack <int> st;
void tarjan(int u) {
dfn[u] = low[u] = ++dtot;
st.push(u), ins[u] = 1;
for (auto v: G[u]) {
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (ins[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if (dfn[u] == low[u]) {
int y; ++scc;
while (y = st.top()) {
ins[y] = 0, st.pop();
be[y] = scc;
if (y == u) break;
}
}
}
void solve() {
int x1 = -inf, x2 = inf, y1 = -inf, y2 = inf;
for (rint i = 1; i <= n; i++) {
ckmax(x1, a[i].x1), ckmax(y1, a[i].y1);
ckmin(x2, a[i].x2), ckmin(y2, a[i].y2);
}
//cerr << "ok1 !\n";
//assert(x1 >= x2 && y1 >= y2);
int tot = 0, min_h = inf;
for (rint i = 1; i <= n; i++) {
vector <int> o = h[i];
// 两条纵边 (0 <= id <= 1)
if (a[i].x1 <= x1 && x1 <= a[i].x2) o.pb(0);
if (a[i].x1 <= x2 && x2 <= a[i].x2) o.pb(1);
// 两条横边 (2 <= id <= 3)
if (a[i].y1 <= y1 && y1 <= a[i].y2) o.pb(2);
if (a[i].y1 <= y2 && y2 <= a[i].y2) o.pb(3);
ckmin(min_h, o.size());
if (o.size() >= 3) { // 一定与一条边有交
//o.clear();
continue;
}
id[i][0] = ++tot, id[i][1] = ++tot;
if (o.size() == 1) add(id[i][1], id[i][0]);
int siz = o.size();
for (rint j = 0; j < siz; j++) {
sl[o[j]].emplace_back(o[j] < 2 ? max(y2, a[i].y1) : max(x2, a[i].x1), id[i][j], id[i][j ^ 1]);
sr[o[j]].emplace_back(o[j] < 2 ? min(y1, a[i].y2) : min(x1, a[i].x2), id[i][j], id[i][j ^ 1]);
}
//o.pb(0);
h[i] = o;
//printf("%d\n", h[i].size());
}
//exit(0);
//cerr << "min_h" << ' ' << min_h << '\n';
//assert(min_h > 0);
//cerr << "ok2 !\n";
for (rint v = 0; v < 4; v++) {
sort(all(sl[v])), sort(all(sr[v]));
int sz_l = sl[v].size(), sz_r = sr[v].size();
for (rint i = 0; i < sz_r; i++) {
pre[v][i + 1] = ++tot;
if (i > 0) add(pre[v][i + 1], pre[v][i]);
add(pre[v][i + 1], thi(sr[v][i]));
}
for (rint i = 0, j = 0; i < sz_l; i++) {
while (j < sz_r && fir(sr[v][j]) < fir(sl[v][i])) j++;
if (j > 0) add(sec(sl[v][i]), pre[v][j]);
}
for (rint i = sz_l - 1; i >= 0; i--) {
suf[v][i] = ++tot;
if (i + 1 < sz_l) add(suf[v][i], suf[v][i + 1]);
add(suf[v][i], thi(sl[v][i]));
}
for (rint i = sz_r - 1, j = sz_l; i >= 0; i--) {
while (j > 0 && fir(sl[v][j - 1]) > fir(sr[v][i])) j--;
if (j < sz_l) add(sec(sr[v][i]), suf[v][j]);
}
}
//printf("tot=%d\n", tot);
//for (rint i = 1; i <= tot; i++) {
// printf("%d\n", G[i].size());
//}
//exit(0);
//cerr << "ok3 !\n";
for (rint i = 1; i <= tot; i++) if (!dfn[i]) {
tarjan(i);
}
//cerr << "ok4 !\n";
vector <int> L(5), R(4);
L[0] = L[1] = y2, L[2] = L[3] = x2;
R[0] = R[1] = y1, R[2] = R[3] = x1;
//cerr << "ok5 !\n";
for (rint i = 1; i <= n; i++) {
if (!id[i][0]) continue;
assert(h[i].size());
int j = h[i][be[id[i][0]] >= be[id[i][1]]]; // 拓扑序反过来
//printf("%d: %d\n", i, be[id[i][0]] >= be[id[i][1]]);
ckmax(L[j], j < 2 ? a[i].y1 : a[i].x1);
ckmin(R[j], j < 2 ? a[i].y2 : a[i].x2);
}
//cerr << "ok6! \n";
assert(L[0] <= R[0] && L[1] <= R[1] && L[2] <= R[2] && L[3] <= R[3]);
printf("%d %d\n", x2, L[1]);
printf("%d %d\n", x1, L[0]);
printf("%d %d\n", L[3], y2);
printf("%d %d\n", L[2], y1);
} int main() {
//freopen("04-14.txt.in", "r", stdin);
//freopen("my.out", "w", stdout);
scanf("%d%d", &n, &K);
for (rint i = 1; i <= n; i++) {
scanf("%d%d%d%d", &a[i].x1, &a[i].y1, &a[i].x2, &a[i].y2);
}
dfs(K);
assert(K == 4);
solve();
return 0;
}

Day1T3 扫除

题目链接:Day1T3 扫除

Solution

Code

咕咕咕

Day2T1 变色龙之恋

题目链接:Day2T1 变色龙之恋

Day2T2 有趣的Joitter交友

题目链接:Day2T2 有趣的Joitter交友

Day2T3 遗迹

题目链接:Day2T3 遗迹

Day3T1 星座3

题目链接:Day3T1 星座3

Day3T2 收获

题目链接:Day3T2 收获

Day3T3 迷路的猫

题目链接:Day3T3 迷路的猫

Day4T1 首都

题目链接:Day4T1 首都

Day4T2 制作团子

题目链接:Day4T2 制作团子

Day4T3 应对方案

题目链接:Day4T3 应对方案

JOISC2020 题解的更多相关文章

  1. JOISC2020 自闭记

    以下是我考场上的思路,很多题都不是正解.对于某些题目,我们使用<代码部落>中的题解,希望大家能够看懂 JOISC2020 Round1 自闭记 T1 11 pts 算法:考虑\(DP\). ...

  2. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  3. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  4. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  5. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  6. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  7. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  8. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  9. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

随机推荐

  1. SVG vs Image, SVG vs Iconfont

    这可能是个别人写过很多次的话题,但貌似由于兼容性的原因?图标的显示还是用着 Iconfont 或者 CSS Sprite 的形式?希望通过自己新瓶装旧酒的方式能重新引导一下问题. SVG vs Ima ...

  2. electron制作聊天界面(仿制qq)

    效果图: 样式使用scss和flex布局 这也是制作IM系统的最后一个界面了!在制作之前参考了qq和千牛 需要注意的点 qq将滚动条美化了 而且在无操作的情况下是不会显示的 滚动条美化 ::-webk ...

  3. 关于CSS的个人理解

    CSS的个人理解 一.概念 层叠样式表,主要由属性和属性值(value)组成.(虽然HTML.CSS对代码大小写不敏感,但是属性和属性值对代码大小写是敏感的) 二.工作方式 1.工作原理 由浏览器将C ...

  4. ES6-11学习笔记--扩展运算符与rest参数

    1.符号都是使用:... 2.扩展运算符:把数组或者类数组展开成用逗号隔开的值 3.rest参数:把逗号隔开的值组合成一个数组   扩展运算符: function foo(a, b, c) { con ...

  5. SimpleDateForma求日期,2008-11月第6周星期日是几号?

    题目4: 巧妙利用SimpleDateFormat根据各种信息求日期.2008-11月第6周的星期日是几号? import java.text.ParseException;import java.t ...

  6. Vue Element ui密码框校验

    <el-form-item prop="repeat_Password" class="userName_color"> <el-input ...

  7. 制作java的docker镜像

    Dockerfile如下: FROM ubuntu:16.04 MAINTAINER tanyiqu ADD jdk-8u231-linux-x64.tar.gz /usr/local/ ENV JA ...

  8. 学习Java必用的9个网站,最后一个最好用!

    Java语言已经成为IT编程界中一种持久的语言,从主要开放源码网站中统计的每月编程语言排名来看,Java一直位居榜首.因此,我们的程序员不能放弃学习Java呀!今日小编为大家整理了几个关于Java学习 ...

  9. python---用顺序表实现队列

    class Queue(object): """队列""" def __init__(self): self.__list = [] def ...

  10. ThingsBoard安装编译搭建环境踩坑记录

    1.首先从github拉下来项目,我们采用源码编译的方式部署 git clone https://github.com/thingsboard/thingsboard.git 2.切换分支 git c ...