Solution - Luogu P11394 [JOI Open 2019] ウイルス実験

news/2024/12/23 21:20:12/文章来源:https://www.cnblogs.com/rizynvu/p/18624939

首先可以根据字符串 \(D\)\(\mathcal{O}(2^c|D|)\)\(c\) 为方向数 \(4\))求出上下左右分别是否被感染时对应的最长连续段长度,用于后面的 check。

考虑到答案要求的最小值,于是可以考虑思考什么样的点不会作为最后的最小值的起始点。
考虑到如果最先感染了点 \(u\),且最终感染了点 \(v\),但是若最先感染了点 \(v\) 却不会感染 \(u\),那么 \(u\) 一定是不优的。
这是因为以 \(v\) 为起始点最后能走到的点的点集一定会是以 \(u\) 为起始点的点集的子集。

于是考虑图论刻画,如果以 \(u\) 为起始点可以感染到 \(v\),那么连边 \(u\to v\)
那么这个连边能发现肯定是有传递性的,即 \(u\to v, v\to w\),则必定有 \(u\to w\)
那么对该有向图缩完点后,可以知道答案必定出现在一个无出边的强连通分量中(有出边往出边走一定更优),且这个强连通分量一定是个团。

所以答案就是这种团的最小大小,而起始点数就是最小大小乘上大小为该大小的这种团的数量。

于是来考虑如何维护这个图和最后的答案的团。

一个想法是肯定这个团对应到网格图上是一个连通块。
于是考虑维护图上的若干个连通块与其对应的为答案的团的点集。
然后去合并连通块,同时合并答案的团的点集。

需要注意的是,这里维护的答案的团的点集只针对当前连通块,并不保证合并之后依然如此(可能答案点集的点不在答案中,不在答案点集的点在答案中)。
且同时,保证连通块内的任意一个点开始扩展都可以扩展到 \(v\)(就可以扩展到整个答案集)。

但是直接维护这个团的点显得有点太麻烦了,考虑用其他的东西去刻画这个团。
能够知道的是,因为这是个团,且不会连向团外的其他点,所以只需要知道这个团内的任意一个点,就可以知道这个团里的点。
即从这个点开始 BFS 往外扩展这个团就可以了。

于是对于一个连通块,可以直接用一个关键点 \(u\) 来表示团。

那接下来就来考虑合并连通块了。
考虑如果以关键点 \(u\) 开始往外扩展团,扩展完团后发现还能继续扩展到另一个连通块,令这一个连通块的关键点是 \(v\)
因为 \(v\) 所在的连通块内的任意一个点开始扩展都能扩展到 \(v\),那么从 \(u\) 扩展就一定可以扩展到 \(v\)
那么就可以直接把 \(u\) 对应的连通块合并到 \(v\) 对应的连通块,且这个时候因为只知道 \(u\) 可以扩展到 \(v\),不知道 \(v\) 是否可以扩展到 \(u\),所以令新的连通块的关键点依然为 \(v\)
如果无法扩展,那么说明当前跑出来的团就是这个团的答案,且不再能扩展了,直接统计这个连通块的贡献即可。

但是如果直接每次选一个没扩展的点向外扩展维护该连通块的关键点对于复杂度不太可接受,因为每次合并关键点就不是当前关键点了,只能重新更换新的关键点跑。

但是注意到同时合并多个连通块是不会对过程产生影响的,那么可以想到 boruvka。
具体来说,可以分轮跑,其中对于每一轮,就为每一个连通块都找到一个要合并上的连通块,然后同时合并,这样子每一轮过后连通块数必定最多是原来的一半,就只会有 \(\mathcal{O}(\log nm)\) 轮。

其实这里应该细说一下同时合并的正确性:
考虑如果连通块 \(u\) 要合并到连通块 \(v\),关键点仍为 \(v\),连边 \(u\to v\),那么这是一颗树 / 基环树:

  • 一颗树。那么对于树边,这相当于一个传递关系传递到根,其中树根已经无法扩展出去了,直接统计贡献一定是没有问题的。
  • 一棵基环树。
    首先对于树,同上就是传递关系传递到环上的节点,没有问题。
    对于环,假设是 \(p_1\to p_2\to \cdots p_n\to p_1\),那么不管从 \(p_{1\sim n}\) 的任何一个点开始,肯定都能扩展到 \(p_{1\sim n}\),于是 \(p_{1\sim n}\) 任意一个点作为关键点都是可行的,所以没有问题。

于是就做完啦,时间复杂度 \(\mathcal{O}(2^c |D| + nmc\log nm)\),其中 \(c = 4\),含义为方向数。

代码写的有点丑了,后面一部分写成了 \(\mathcal{O}(nmc^2\log nm)\)

#include<bits/stdc++.h>
constexpr int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
constexpr int maxL = 2e5 + 10, maxn = 800 + 10;
char str_[maxL], C[5] = "NSWE";
int str[maxL], mxt[16];
int U[maxn][maxn];
int fx[maxn][maxn], fy[maxn][maxn];
int vis[maxn][maxn], T;
inline std::pair<int, int> getfa(int x, int y) {if (fx[x][y] != x || fy[x][y] != y) {std::tie(fx[x][y], fy[x][y]) = getfa(fx[x][y], fy[x][y]);}return std::make_pair(fx[x][y], fy[x][y]);
}
int main() {int L, n, m;scanf("%d%d%d%s", &L, &n, &m, str_);for (int i = 0; i < L; i++) {while (C[str[i]] != str_[i]) str[i]++;}for (int s = 0; s < 16; s++) {int c = 0;for (int i_ = 0; i_ < L + L; i_++) {int i = i_ % L;if (s >> str[i] & 1) {c++;} else {mxt[s] = std::max(mxt[s], c), c = 0;}}mxt[s] = std::max(mxt[s], c);}for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {scanf("%d", &U[i][j]);if (U[i][j]) {U[i][j] = std::min(U[i][j], L);std::tie(fx[i][j], fy[i][j]) = std::make_pair(i, j);} else {U[i][j] = 1e9;}}}int ans = 1e9, cnt = 0;while (true) {std::vector<std::pair<int, int> > S;for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) {if (std::make_pair(i, j) == getfa(i, j)) {S.emplace_back(i, j);}}if (S.empty()) break;std::vector<std::pair<int, int> > to(S.size(), std::make_pair(-1, -1));for (size_t id = 0; id < S.size(); id++) {auto [sx, sy] = S[id];std::queue<std::pair<int, int> > Q;vis[sx][sy] = ++T, Q.emplace(sx, sy);int siz = 0;while (! Q.empty()) {auto [i, j] = Q.front(); Q.pop();siz++;for (int k : {0, 1, 2, 3}) {int x = i + dx[k], y = j + dy[k];if (x < 1 || y < 1 || x > n || y > m || vis[x][y] == T) continue;int s = 0;for (int h : {0, 1, 2, 3}) {int px = x + dx[h], py = y + dy[h];if (px < 1 || py < 1 || px > n || py > m) continue;s |= (vis[px][py] == T) << h;}if (U[x][y] <= mxt[s]) {vis[x][y] = T;if (std::make_pair(sx, sy) == getfa(x, y)) {Q.emplace(x, y);} else {to[id] = {x, y};}}}}if (to[id] == std::make_pair(-1, -1)) {if (siz < ans) ans = siz, cnt = 0;if (siz == ans) cnt += ans;std::tie(fx[sx][sy], fy[sx][sy]) = std::make_pair(0, 0);}}for (size_t i = 0; i < S.size(); i++) {if (to[i] != std::make_pair(-1, -1)) {auto [sx, sy] = S[i];auto [tx, ty] = to[i];std::tie(fx[sx][sy], fy[sx][sy]) = getfa(tx, ty);}}}printf("%d\n%d\n", ans, cnt);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/857667.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

校园二手交易平台UML图

类图:时序图: 买家买商品:买家撤回:用户更新:用户登录:卖家发布:用例图:

2 升力线理论

2 升力线理论 2.1 减阻 阻力 什么是阻力?阻力是阻止主要运动(位移向量)的力。 可以用一个简单的公式描述阻力: \[\begin{equation}\overrightarrow{R_2}-\overrightarrow{R_1}\propto\vec{T}-\vec{D} \end{equation} \]这里的R是反作用力(reactive force),T是推力(thru…

python网络编程之sse

服务端:from fastapi import FastAPI from fastapi.responses import StreamingResponse from fastapi.middleware.cors import CORSMiddleware import timeapp = FastAPI()# 允许所有来源的跨域请求 app.add_middleware(CORSMiddleware,allow_origins=["*"], # 允…

Array Collapse

前言 调 \(C\) 快魔怔了, 还是先来打这个 思路 方法 \(1\) : 笛卡尔树 看到这种类 \(\rm{RMQ}\) 问题直接一个笛卡尔树起手, 恰好 \(p\) 是不重的, 那么更方便了啊 搞出树树挖下性质 例如样例中的 4 2 4 1 3你注意到每次删除操作相当于选择一个键值段, 然后只保留这一段的根节点…

禅道bug增加自定义字段

禅道版本 18.9 需求 给禅道的bug模块,增加自定义字段。目前主要增加“发现阶段”、“所属环境”、“出现频率” 增加bug的类型 在bug列表增加搜索:“发现阶段”、“所属环境”、“出现频率” 在测试报告增加模块:“发现阶段”、“所属环境”、“出现频率”禅道开发手册 http…

php网络编程tcp

服务端:<?php $server = new Swoole\Server(127.0.0.1, 9501);$server->set([worker_num => 8, // worker进程数 cpu1-4倍max_request => 10000, // 根据内存定义 https://wiki.swoole.com/#/server/setting// open_eof_check => true,// package_eof => &…

php网络编程swoole websocket

服务端:<?php use Swoole\WebSocket\Server;// 创建 HTTP 服务器 $server = new Server(127.0.0.1, 8888, SWOOLE_PROCESS, SWOOLE_SOCK_TCP);$server->on(start, function ($server) {//print_r($server);echo "Swoole websocket server is started at ws://127.…

php网络编程swoole udp

服务端:<?php $server = new Swoole\Server(127.0.0.1, 9504, SWOOLE_PROCESS, SWOOLE_SOCK_UDP);$server->on(start, function ($server) {echo "UDP Server is started at udp://127.0.0.1:9504\n"; });$server->on(packet, function ($server, $data, …

第36次ccf-csp题解(思维)

比赛链接 https://sim.csp.thusaac.com/contest/36/home比赛感受这会刚打完上海icpc,比起区域赛的题,这个简单太多了。 感受还不错,写的很顺手。除了第3题,其他3题都是一发过。 刷题得长期刷。 A题 移动题意:f : y+1 ;  b : y-1 ;   l : x-1 ;  r : x+1 一个简单的模…

php网络编程swoole http

服务端:<?php use Swoole\Http\Server; use Swoole\Http\Request; use Swoole\Http\Response;// 创建 HTTP 服务器 $server = new Server(127.0.0.1, 9501);$server->on(start, function ($server) {//print_r($server);echo "Swoole http server is started at h…