T1、迷宫

一个 $ n \times m  (n \leq 5, m \leq 10 ^ 5) $ 的矩阵,\(0\) 表示格子不能走,\(1\) 表示格子可以走,只能向上、下、右三个方向走。有 $ q  (q \leq 5 \times 10 ^ 4) $ 次操作,操作有两种:
1、修改某个格子的类型;
2、查询从 $ (a, b) $ 到 \((c, d)\) 的最短路,不可达输出 \(-1\)。 (保证后者在前者右边)。

\(Sol\):

观察到 \(n \leq 5\),这是很重要的提示。
在左右方向上建线段树,线段树每个叶子节点为一个矩阵,该矩阵描述了这一列上点的连通关系,特别地,若该列某一行的格子不能走,它到自己在矩阵中应表示为不可到达;
合并时枚举中间点 \(n ^ 3\) 暴力合并。
然而我考场上写了常数较大的做法:每个叶子节点的矩阵描述这一列到下一列的连通关系,合并同理;这样写修改时要改两个点,然后就没了。

\(Source\):

#include <cstdio>
#include <cstring>
#include <algorithm>
int in() {int x = 0; char c = getchar(); bool f = 0;while (c < '0' || c > '9')f |= c == '-', c = getchar();while (c >= '0' && c <= '9')x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();return f ? -x : x;
}const int N = 2e5 + 5;int n, m, q, mp[7][N];template<typename T>inline void chk_min(T &_, T __) {_ = !~_ ? __ : (_ < __ ? _ : __);
}
struct node {int a[6][6];node () {memset(a, -1, sizeof(a));}inline int* operator [] (const int x) {return a[x];}inline node operator + (node b) const {node ret;for (int k = 1; k <= n; ++k)for (int i = 1; i <= n; ++i)if (~a[i][k])for (int j = 1; j <= n; ++j)if (~b[k][j])chk_min(ret[i][j], a[i][k] + b[k][j] + 1);return ret;}
} ;
struct segment_tree {node t[N << 2];void init(int x, int p) {for (int i = 1, j; i <= n; ++i) {for (j = i; j <= n && mp[j][x]; ++j)t[p][i][j] = j - i;for (; j <= n; ++j)t[p][i][j] = -1;for (j = i; j && mp[j][x]; --j)t[p][i][j] = i - j;for (; j; --j)t[p][i][j] = -1;}}inline void push_up(int p) {t[p] = t[p << 1] + t[p << 1 | 1];}void build(int tl, int tr, int p) {if (tl == tr)return init(tl, p);int mid = (tl + tr) >> 1;build(tl, mid, p << 1), build(mid + 1, tr, p << 1 | 1);push_up(p);}void modify(int pos, int tl, int tr, int p) {if (tl == tr)return init(tl, p);int mid = (tl + tr) >> 1;if (mid >= pos)modify(pos, tl, mid, p << 1);elsemodify(pos, mid + 1, tr, p << 1 | 1);push_up(p);}node query(int l, int r, int tl, int tr, int p) {if (l <= tl && tr <= r)return t[p];int mid = (tl + tr) >> 1;if (mid < l)return query(l, r, mid + 1, tr, p << 1 | 1);if (mid >= r)return query(l, r, tl, mid, p << 1);return query(l, r, tl, mid, p << 1) +query(l, r, mid + 1, tr, p << 1 | 1);}
} T;int main() {//freopen("in", "r", stdin);freopen("maze.in", "r", stdin);freopen("maze.out", "w", stdout);n = in(), m = in(), q = in();for (int i = 1; i <= n; ++i)for (int j = 1; j <= m; ++j)mp[i][j] = in();T.build(1, m, 1);int a, b, c, d;node res;while (q--) {if (in() == 1) {a = in(), b = in();mp[a][b] ^= 1;T.modify(b, 1, m, 1);} else {a = in(), b = in(), c = in(), d = in();res = T.query(b, d, 1, m, 1);printf("%d\n", res[a][c]);}}return 0;
}

T2、猛汉王

平面上有 \(n \ (n \leq 10 ^ 5)\) 个黑点,\(m \ (n \leq 10 ^ 5)\) 个白点,若黑点 \(x\) 与白点 \(y\) 的曼哈顿距离小于等于 \(d \ (d \leq 10 ^ 9)\),则 \(x\) 向 \(y\) 连边,否则 \(y\) 向 \(x\) 连边。
同色点之间的连边方向不确定,求至少有一个黑点和白点的三元环的最小值和最大值。

\(Sol\):

显然地,三元环上有两个同色点。
由于我们不关心异色边是怎么连的,只关心是否能为同向环上的边,所以黑色点和白色点同理。
记 \(cover(x)\) 表示 \(x\) 能覆盖的白色点,\(cover ( x, y )\) 表示 \(x, y\) 共同覆盖到的白色点。
以下以最大值为例 (最小值同理)。
\[ \begin{eqnarray} Ans &=& \sum_{x, y \in S} \max \{cover(x) - cover{(x,y)}, cover(y) - cover(x, y) \} \notag \\ &=& \sum_{x, y \in S} \max \{ cover(x), cover(y) \} - \sum_{x, y \in S} cover(x, y) \notag \\ &=& \sum_{x, y \in S} \max \{ cover(x), cover(y) \} - \sum_{x \in S} \binom{cover(x)}{2} \notag \\ \end{eqnarray} \]
只要求出 \(cover(x)\) 即可;
扫描线维护以下就行了。

\(Source\):

#include <cstdio>
#include <cstring>
#include <algorithm>
int in() {int x = 0; char c = getchar(); bool f = 0;while (c < '0' || c > '9')f |= c == '-', c = getchar();while (c >= '0' && c <= '9')x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }const int N = 1e5 + 5;
struct node {int x, y;
} a[N], b[N];
struct options {long long x; int y, z, id;int typ;
} opt[N * 3];int n, m, d, nn, cntx[N], cnty[N];
long long ans_min, ans_max;long long tmp[N * 3];
inline bool cmpx(const options &i, const options &j) {if (i.x == j.x)return i.typ == 0 ? 1 : j.typ != 0;return i.x < j.x;
}
void prep() {nn = 0;for (int i = 1; i <= m; ++i)tmp[i] = b[i].y;for (int i = 1; i <= n; ++i)tmp[i + m] = 1ll * a[i].y - d;for (int i = 1; i <= n; ++i)tmp[i + n + m] = 1ll * a[i].y + d;std::sort(tmp + 1, tmp + 1 + n + n + m);nn = std::unique(tmp + 1, tmp + 1 + n + n + m) - tmp - 1;for (int i = 1; i <= m; ++i) {opt[i].typ = opt[i].id = 0;opt[i].x = b[i].x;opt[i].y = std::lower_bound(tmp + 1, tmp + 1 + nn, b[i].y) - tmp;opt[i].z = 0;}for (int i = 1; i <= n; ++i) {opt[i + m].typ = -1;opt[i + m].id = i;opt[i + m].x = 1ll * a[i].x - d - 1;opt[i + n + m].typ = 1;opt[i + n + m].id = i;opt[i + n + m].x = 1ll * a[i].x + d;opt[i + m].y = opt[i + n + m].y = std::lower_bound(tmp + 1, tmp + 1 + nn, 1ll * a[i].y - d) - tmp;opt[i + m].z = opt[i + n + m].z = std::lower_bound(tmp + 1, tmp + 1 + nn, 1ll * a[i].y + d) - tmp;}std::sort(opt + 1, opt + 1 + n + n + m, cmpx);
}struct binary_index_tree {int a[N * 3];inline void init() { memset(a, 0, sizeof(a)); }void insert(int p, int k) { for (; p <= nn; p += (p & -p)) a[p] += k; }int ask(int p, int ret = 0) { for (; p; p -= (p & -p)) ret += a[p]; return ret; }
} bit;void work() {prep();bit.init();for (int i = 1; i <= n + n + m; ++i) {if (!opt[i].typ) {bit.insert(opt[i].y, 1);} else {cntx[opt[i].id] += opt[i].typ * (bit.ask(opt[i].z) - bit.ask(opt[i].y - 1));}}
}int main() {//freopen("in", "r", stdin);freopen("mhw.in", "r", stdin);freopen("mhw.out", "w", stdout);n = in(), m = in(), d = in();for (int i = 1; i <= n; ++i) {a[i] = (node){in(), in()};a[i] = (node){a[i].x + a[i].y, a[i].x - a[i].y};}for (int i = 1; i <= m; ++i) {b[i] = (node){in(), in()};b[i] = (node){b[i].x + b[i].y, b[i].x - b[i].y};}work();std::swap(a, b);std::swap(n, m);std::swap(cntx, cnty);work();std::sort(cntx + 1, cntx + 1 + n);std::sort(cnty + 1, cnty + 1 + m);for (int i = 1; i <= n; ++i) {ans_min += 1ll * cntx[i] * (n - i);ans_min -= 1ll * cntx[i] * (cntx[i] - 1) / 2;ans_max += 1ll * cntx[i] * (i - 1);ans_max -= 1ll * cntx[i] * (cntx[i] - 1) / 2;}for (int i = 1; i <= m; ++i) {ans_min += 1ll * cnty[i] * (m - i);ans_min -= 1ll * cnty[i] * (cnty[i] - 1) / 2;ans_max += 1ll * cnty[i] * (i - 1);ans_max -= 1ll * cnty[i] * (cnty[i] - 1) / 2;}printf("%lld %lld\n", ans_min, ans_max);return 0;
}

T3、工厂

给定一个二分图,可以加边,使得二分图的所有极大匹配都是完美匹配。

\(Sol\):

先证明一件事:当且仅当这个二分图里的每个联通块左右点数相同且边都是连满的 \((A)\),满足题意 \((B)\)。
由 \(B\) 到 \(A\) 是显然的,不再赘述;
由 \(A\) 到 \(B\) 可以用反证法:
若联通块中有两个异侧点 \(a\),\(b\) 之间没有连边,找到一条从 \(a\) 到 \(b\) 的路径,把奇数边加入匹配边集,在此基础上找到一个极大匹配,找到的应该是完美匹配;将路径上奇数边取出匹配边集,偶数边加入,此时也是一个极大匹配但不是完美匹配。
\(QED\)

将几个联通块合并的代价为 \(( \sum x_i ) ^ 2\)。
记 \(f_{s,i}\) 表示当前选出联通块集合为 \(s\),已经安排了点数和为 \(2i\) 的联通块 (使它们满足上述条件) 的最小代价。
转移有两种:
\[ \begin{eqnarray} f_{s \bigcup \{ x \},i} &=& \min(f_{s \bigcup \{ x \}, i}, f_{S,i}) \notag \\ f_{s, i} &=& \min_{j = 0} ^ {i - 1} \{ f_{s,j} + (i - j) ^ 2 \} \ , (\Sigma_{x \in s} = \Sigma_{y \in s}) \notag \end{eqnarray} \]
由于状态数太多,这样也过不了,可以优化状压的方式;
我们只关心每一种联通块 (以左右点数分类) 有几个,可以用变进制数来优化状态数;
出题人告诉我们最多有 \(172032\) 种状态。

\(Source\):

#include <cstdio>
#include <cstring>
#include <algorithm>
int in() {int x = 0; char c = getchar(); bool f = 0;while (c < '0' || c > '9')f |= c == '-', c = getchar();while (c >= '0' && c <= '9')x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }const int N = 35, inf = 0x3f3f3f3f;int n, m, mp[N << 1][N << 1], tmp_x, tmp_y, init_edge, buc[N][N], pre[N << 1], f[172033][N], num[N << 1];
bool vis[N << 1];struct node {int x, y;inline bool operator < (const node &b) const {return buc[this->x][this->y] < buc[b.x][b.y];}inline bool operator == (const node &b) const {return this->x == b.x && this->y == b.y;}
} a[N + N];void prep(const int u) {vis[u] = 1;if (u <= n)++tmp_x;else++tmp_y;for (int i = 1; i <= mp[u][0]; ++i)if (!vis[mp[u][i]])prep(mp[u][i]);
}int main() {//freopen("in", "r", stdin);freopen("factory.in", "r", stdin);freopen("factory.out", "w", stdout);n = in();for (int i = 1; i <= n; ++i)for (int j = 1; j <= n; ++j) {char c = getchar();while (c < '0' || c > '1')c = getchar();if (c == '1') {mp[i][++mp[i][0]] = j + n;mp[j + n][++mp[j + n][0]] = i;}init_edge += c == '1';}for (int i = 1; i <= n + n; ++i)if (!vis[i]) {tmp_x = tmp_y = 0;prep(i);++buc[tmp_x][tmp_y];}for (int i = 0; i <= n; ++i)for (int j = 0; j <= n; ++j)if (buc[i][j])a[++m] = (node){i, j};std::sort(a + 1, a + 1 + m);m = std::unique(a + 1, a + 1 + m) - a - 1;pre[1] = 1;for (int i = 2; i <= m + 1; ++i)pre[i] = pre[i - 1] * (buc[a[i - 1].x][a[i - 1].y] + 1);memset(f, inf, sizeof(f));f[0][0] = 0;int nowx, nowy;for (int s = 0; s < (pre[m + 1]); ++s) {nowx = nowy = 0;for (int i = 1; i <= m; ++i)num[i] = s % pre[i + 1] / pre[i];for (int i = 1; i <= m; ++i)nowx += num[i] * a[i].x, nowy += num[i] * a[i].y;if (nowx == nowy)for (int i = 0; i < nowx; ++i)chk_min(f[s][nowx], f[s][i] + (nowx - i) * (nowx - i));for (int i = 1; i <= m; ++i)if (num[i] < buc[a[i].x][a[i].y])for (int j = 0; j <= n; ++j)chk_min(f[s + pre[i]][j], f[s][j]);}printf("%d\n", f[pre[m + 1] - 1][n] - init_edge);return 0;
}

转载于:https://www.cnblogs.com/15owzLy1-yiylcy/p/11348880.html

「2019纪中集训Day12」解题报告相关推荐

  1. 「2019纪中集训Day7」解题报告

    T1.小L的数列 给一个数列 \(\{f_i\}\): \[ f_i = \prod_{j = 1}^{j \leq k} f_{i - j}^{b_j}, \ (i > k) \] 现在给定数 ...

  2. 「2019纪中集训Day23」解题报告

    T1.矩阵乘法 题目链接 给定一个 \(n \times n \ (n \leq 500)\) 的矩阵 \((a_{i,j} \leq 10 ^ 9)\),\(q \ (q \leq 6 \times ...

  3. 2019纪中集训总结

    其实用一句话总结的话,那么就是: We still have a long way to go. 来到纪中,才知道全国还有这么多优秀的OI神犇,才知道自己不过是井下之蛙,才知道自己之前的幼自满的幼稚. ...

  4. 8.12 纪中集训 Day12

    T1少女觉 Description 在幽暗的地灵殿中,居住着一位少女,名为古明地觉. 据说,从来没有人敢踏入过那座地灵殿,因为人们恐惧于觉一族拥有的能力--读心. 掌控人心者,可控天下.   咳咳. ...

  5. 2019寒假纪中集训总结学期总结(流水账)

    学期总结 这学期上了初三,学校的初.高中校区对调,我们的班主任也由一个生物老师换成了一个化学老师. 之前的班主任比较年轻,跟我们这群学生有这很好的感情,亦师亦友,陪伴我们度过了几乎没有中考压力的初一. ...

  6. 用typescript完成倒计时_「2019 JSConf.Hawaii - Brie.Bunge」大规模应用 TypeScript

    特别说明 这是一个由 simviso 团队对 JSConf.Hawaii 中关于 TypeScript 相关话题进行翻译的文档,内容并非直译,其中有一些是笔者自身的思考.分享者为 Brie.Bunge ...

  7. 「2019 JSConf.Hawaii - Brie.Bunge」大规模应用 TypeScript

    特别说明 这是一个由 simviso 团队对 JSConf.Hawaii 中关于 TypeScript 相关话题进行翻译的文档,内容并非直译,其中有一些是笔者自身的思考.分享者为 Brie.Bunge ...

  8. 倒计时 3 天!「2019 嵌入式智能国际大会」全日程大公开!

    立即抢购:https://t.csdnimg.cn/otBk 还有3天,大伙期待的「2019嵌入式智能国际大会」正式开幕了! 2019年12月6日-7日,我们在深圳市人才研修院见! 大会以" ...

  9. 8.3折特惠票仅剩3天!「2019 嵌入式智能国际大会」全日程大公开!

    8.3折特惠票仅剩3天 立即抢购:https://t.csdnimg.cn/otBk 还有5天,大伙期待的「2019嵌入式智能国际大会」正式开幕了! 2019年12月6日-7日,我们在深圳市人才研修院 ...

最新文章

  1. linux 根目录下的子目录的意义
  2. MVC-Razor(3)
  3. Android开发返回拍摄的图片
  4. 查询过去一个月有付款mysql_MySQL_mysql 月份查询该月有付款的数据,ktime 开始时间串 dtime 到期时间 - phpStudy...
  5. python 主语_前深度学习时代--FFM模型的原理与Python实现
  6. java使用varargs,Java 实例 – Varargs 可变参数使用 - Java 基础教程
  7. 大话数据结构:平衡二叉排序树
  8. 在HTML中使用javascript (js高级程序设计)
  9. swf文件在线预览 html,在线浏览swf文件
  10. PHP: stdclass, 数组转成对象
  11. 百万奖池大赛 | 交通事件、医学病理、违法广告检测等,2020首届江苏大数据开发与应用大赛启动...
  12. 为了分析WebRTC, 重学Windows开发
  13. vue element new vue const
  14. ROS的学习(九)理解ROS的参数
  15. wpf之auto与*的区别
  16. 带着这篇去通关所有Handler的提问(三)
  17. 如何让循环里面语句执行完之后再去循环第二次_Go循环语句的使用
  18. MathorCup竞赛任务分配
  19. SSH中 三大框架的各自的作用及好处
  20. 计算机网络实验4 — 网线制作

热门文章

  1. 解决支付宝验证失败sign check fail: check Sign and Data Fail
  2. 数据预处理(三)——数据集成
  3. 品读《你不努力,谁也给不了你想要的生活》
  4. 叮咚~您的新年礼物到啦,请查收:虎来喽----Python打造虎年祝福神器
  5. 【ES6学习】对象的解构赋值
  6. Android的富文本
  7. 酶促反应动力学_酶促反应动力学讲解.ppt
  8. Java实体类转Map、Map转实体类
  9. php mysql函数未定义,关于php:Wierd和Annoying错误:调用未定义的函数mysql_query()...
  10. 关于鼠标手的症状和恢复方法