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. java中请给出一个return this的例子。

    [新手可忽略不影响继续学习]下面例子中setYear中的return this;返回了一个指向对象的指针,this.setMonth(8).setDay(20);是合法的,如果像原来的例子一样什么都不 ...

  2. PL/SQL中的 not

    ELECT * FROM table_name WHERE column_name not like'%山%' 這時出現了column_name中為null值的情況也被剔掉了. 原因是:在SQL的表達 ...

  3. 小程序中webview内嵌h5页面

    小程序内嵌h5页面跳转小程序指定页面,  需要引用  JSSDK:   <script src="https://res.wx.qq.com/open/js/jweixin-1.3.2 ...

  4. Mybatis更新和删除数据

    接上文->Mybatis快速入门<- 1.在UserMapper.xml配置更新和删除 <!-- 更新操作--> <update id="update" ...

  5. 面试 | Java 算法的 ACM 模式

    (Java 算法的 ACM 模式) 前言 经常在 LeetCode 上用核心代码模式刷题的小伙伴突然用 ACM 模式可能会适应不过来,把时间花在输入输出上很浪费时间,因此本篇笔记对 Java 算法的 ...

  6. Bootstarp框架用法

    Bootstrap框架 Bootstrap框架 2.X 3.X 4.X # 推荐使用3.X版本 使用框架调整页面样式一般都是操作标签的class属性即可 bootstrap需要依赖于jQuery才能正 ...

  7. 状态机引擎在vivo营销自动化中的深度实践 | 引擎篇02

    本文是<vivo营销自动化技术解密>的第3篇文章,分析了营销自动化业务背景和状态机引入原因.状态机的三种基本实现方式,同时介绍了几种业界流行的开源状态机框架实现和特点,以及在项目开发过程中 ...

  8. ZABBIX Proxy容器启动的配置过程

    ZABBIX Proxy容器启动的配置过程 环境介绍 版本 zabbix6 zabbix server 与 zabbix proxy 非同一台主机,zabbix proxy为主动方式提交给server ...

  9. canvas基础简单易懂教程(完结,多图)

    目录 Canvas学习 一. Canvas概述 1.1 Hello world 1.2 Canvas的像素化 1.3 Canvas的动画思想 1.4 面向对象思维实现canvas动画 二.Canvas ...

  10. python中一些列表知识

    列表 序列是 Python 中最基本的数据结构. 序列中的每个值都有对应的位置值,称之为索引,第一个索引是 0,第二个索引是 1,依此类推. Python 有 6 个序列的内置类型,但最常见的是列表和 ...