Codeforces Round 916 (Div. 3) G2. Light Bulbs (Hard Version) (强连通分量)

原题链接:G2. Light Bulbs (Hard Version)


题目大意:


n n n 种颜色,每种颜色都有两个灯泡,灯泡都排成一行。

最初所有灯都是关闭的,你可以选择任意几个灯泡使它们打开,然后你可以做以下操作。

  • 选择两个灯泡 i , j i,j i,j ,它们 同色,且其中一个灯泡亮了,你就可以打开另一个。
  • 选择三个灯泡 i , j , k i,j,k i,j,k,且 i , k i,k i,k 同色且都亮了,并且 i < j < k i < j < k i<j<k ,则可以点亮灯泡 j j j

现在希望你选择一些灯泡,并且在一定的顺序操作后,可以使得所有灯泡都被点亮。

现在询问你:

  • 最少需要点亮多少个灯泡,才能使得所有的灯泡都被点亮。
  • 在满足最少数量的前提下,有多少种选择灯泡的方法,使得所有的灯泡都被点亮,对 998 998 998 244 244 244 353 353 353 取模后输出。

解题思路:


我们手玩一下,发现几个情况,无论怎么给出序列,都是下面几种情况的拼接:

假设序列是: [ 1 , 2 , 3 , 1 , 2 , 3 ] [1,2,3,1,2,3] [1,2,3,1,2,3]

我们选择 1 1 1 ,那么区间 [ 1 , 4 ] [1,4] [1,4] 所有的灯泡都能被点亮,而颜色 2 , 3 2,3 2,3 有一个端点被点亮了,所以它们的另一个端点也能被点亮。同理,选择 2 , 3 2,3 2,3 作为开始的灯泡也是一样的,我们这样操作能点亮的区间是整个 [ 1 , 6 ] [1,6] [1,6] ,而且是最小操作。

假设序列是: [ 1 , 2 , 3 , 3 , 1 , 2 ] [1,2,3,3,1,2] [1,2,3,3,1,2]

同样的,选择 1 , 2 1,2 1,2 ,就能点亮所有的灯泡,但我们如果选 3 3 3 ,它只会点亮 [ 3 , 4 ] [3,4] [3,4] 这个区间,还要额外再选 1 , 2 1,2 1,2 才能把整个序列都点亮,显然不是最小方案。

注意到,我们只需要开局选择点亮一个灯泡,之后就可以操作 2 2 2 ,操作 1 1 1 ,操作 2 2 2 . . . ... ... ,这样循环下去,最重要的还是最初怎么选点来执行操作 2 2 2

我们把题意转化一下,把每个颜色 i i i 看成是一个节点 i i i ,当点 i i i 被选了,就可以同时去选择一些在区间 [ l i , r i ] [l_{i}, r_{i}] [li,ri] 之内的点 j j j ,但点 j j j 不一定能选回点 i i i ,这是一个有向图的形式。

如果按照这样的思路的话,我们就可以按照这样的情况画出上面两种情况的图:

对于第一个情况:

在这里插入图片描述
对于这种情况来说,我们无论最开始先选 1 , 2 , 3 1,2,3 1,2,3 的任意一个,都能把 1 , 2 , 3 1,2,3 1,2,3 点亮,因为他们同属于一个强连通分量。

对于第二个情况:

在这里插入图片描述
对于这种情况来说,我们无论最开始先选 1 1 1 ,还是 2 2 2 都能把 1 , 2 , 3 1,2,3 1,2,3 点亮,因为 1 , 2 1,2 1,2 属于同一个强连通分量,并且 3 3 3 1 , 2 1,2 1,2 能到达的点。

这启发我们做一个事情,跑强连通分量,然后缩点,同时记录缩点后的每个强连通分量里有多少个点,缩点完后的图一定是一张 D A G DAG DAG 图。

考虑缩点后的 D A G DAG DAG 图,我们想要选择最少的点使得整张图都被点亮,就只用选择那些入度为 0 0 0 的点,因为除了开始就点亮以外,没有其他办法能点亮它们。

入度为 0 0 0 的点的个数,就是我们要的最小操作数。

那么方案数呢?

也很简单,因为入度为 0 0 0 的点必选,且每个点要么是一个强连通分量要么是原图上的点,如果是强连通的点,比如上面的第一个样例 1 → 2 1 \rightarrow 2 12 2 → 3 2 \rightarrow 3 23 3 → 1 3 \rightarrow 1 31,我们会缩成一个点,设为 X X X,且点 X X X 包含原图的点的数量为 3 3 3 ,所以我们有三种方案。

同理上图的第二个样例的方案数就是 2 2 2

那么答案按乘法原理,就是所有入度为 0 0 0 的点的方案的乘积。

那么一个点向区间连边呢?这是个很典型的 t r i c k trick trick ,我们用 线段树优化建图 就好了。

要注意的是,如果用线段树优化建图,我们首先会造出一个虚拟图出来。

虚拟图上有很多不属于统计的范围内,但是入度为 0 0 0 的点,我们要把它们先删去,否则会影响答案,这里用拓扑排序删点就好了。

每个点建最多 O ( log ⁡ n ) O(\log n) O(logn) 条边,一共有 n n n 个点,而跑 T a r j a n Tarjan Tarjan O ( V + E ) O(V+E) O(V+E) 的。

所以时间复杂度为: O ( n log ⁡ n ) O(n \log n) O(nlogn)

AC代码:

#include <bits/stdc++.h>
using namespace std;using PII = pair<int, int>;
using i64 = long long;//强连通分量板子
struct SCC {int n, c_scc, idx;vector<int> stk;vector<int> dfn, low, scc, siz;vector<vector<int>> g;SCC() {};SCC(int _) { init(_); }void init(int _) {this->n = _;g.assign(_ + 1, {});dfn.resize(_ + 1);low.resize(_ + 1);scc.resize(_ + 1);siz.resize(1);stk.clear();idx = c_scc = 0;}void addEdge(int u, int v) {g[u].emplace_back(v);}void DFS(int u) {dfn[u] = low[u] = ++idx;stk.emplace_back(u);for (auto& v : g[u]) {if (!dfn[v]) {DFS(v);low[u] = min(low[u], low[v]);} else if (!scc[v]) {low[u] = min(low[u], dfn[v]);}}if (dfn[u] == low[u]) {int top = -1, cnt = 0; ++c_scc;while (top != u) {top = stk.back(); stk.pop_back();scc[top] = c_scc; ++cnt;}siz.emplace_back(cnt);}}void work() {for (int i = 1; i <= n; ++i) {if (!dfn[i]) DFS(i);}}
};const int mod = 998244353;void solve() {int n;cin >> n;n <<= 1;SCC g(n * 4);vector<PII> line(n >> 1);for (int i = 1; i <= n; ++i) {int x;cin >> x;auto& [l, r] = line[--x];if (!l) {l = i;} else {r = i;}}//build建虚拟图 那么叶子节点的节点编号就对应我们的 1,2,...,n 号点了vector<int> leaf(n + 1);auto build = [&](auto self, int k, int l, int r) -> void {if (l == r) {leaf[l] = k;return;}int mid = l + r >> 1;self(self, k << 1, l, mid);self(self, k << 1 | 1, mid + 1, r);g.addEdge(k, k << 1);g.addEdge(k, k << 1 | 1);};build(build, 1, 1, n);//线段树优化建图auto connect = [&](auto self, int k, int l, int r, int x, int y, int node) -> void {if (l >= x && r <= y) {g.addEdge(node, k);return;}int mid = l + r >> 1;if (x <= mid) self(self, k << 1, l, mid, x, y, node);if (y > mid) self(self, k << 1 | 1, mid + 1, r, x, y, node);};//每个点 i 向区间 [l,r] 用线段树优化建图for (auto& [l, r] : line) {connect(connect, 1, 1, n, l, r - 1, leaf[r]);connect(connect, 1, 1, n, l + 1, r, leaf[l]);}g.work();//记录每个强连通分量有多少个原图内的点vector<int> cnt(g.c_scc + 1);for (int i = 1; i <= n; ++i) {++cnt[g.scc[leaf[i]]];}vector<int> in(g.c_scc + 1);//建缩点后的图:vector<vector<int>> G(g.c_scc + 1);for (int i = 1; i <= n * 4; ++i) {for (auto& v : g.g[i]) {if (g.scc[i] != g.scc[v]) {G[g.scc[i]].emplace_back(g.scc[v]);++in[g.scc[v]];}}}//由于我们是在线段树上的虚拟图跑的Tarjan 所以我们要除去那些没用的点//只保留 缩点后点内至少有一个原图的点 的那些点queue<int> que;for (int i = 1; i <= g.c_scc; ++i) {if (!in[i]) {que.push(i);}}while (que.size()) {int u = que.front(); que.pop();for (auto& v : G[u]) {if (--in[v] == 0) {if (!cnt[v]) {que.push(v);}}}}//如果入度为0且是合法点 即我们缩点点内至少有一个原图的点才是符合统计范围内的点i64 ans1 = 0, ans2 = 1;for (int i = 1; i <= g.c_scc; ++i) {if (!in[i] && cnt[i]) {++ans1;ans2 = ans2 * cnt[i] % mod;}}cout << ans1 << " " << ans2 << '\n';
}signed main() {ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int t = 1; cin >> t;while (t--) solve();return 0;
}

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

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

相关文章

Jmeter系列(1)Mac下载安装启动

目录 Jmeter下载安装启动下载启动 Jmeter下载安装启动 注意⚠️&#xff1a;使用jmeter需要有java环境 下载 官网下载地址&#xff1a;https://jmeter.apache.org/ 会看到这里有两个版本&#xff0c;那么有什么区别么&#xff1f; Binaries是可执行版&#xff0c;直接下载解…

视觉盛宴!莱佛士学生作品登上《VOGUE》杂志

《VOGUE》杂志成立于1892年&#xff0c;是世界上最重要的杂志品牌之一&#xff0c;被公认为全世界最领先的时尚杂志&#xff0c;有着“全球时尚圣经”之称。该杂志介绍世界妇女时尚&#xff0c;包括美容、服装、服饰、珠宝、保健、健美、旅行、艺术等各个方面。 这期杂志新加坡…

SpringCache缓存专题

SpringCache缓存专题 学习目标 1、理解缓存存在的意义 2、掌握redis与SpringCache的集成方式 3、掌握SpringCache注解的使用 4、掌握项目集成SpringCache流程 第一章 基于SpringCache缓存方案 1.为什么需要缓存 ​ 前台请求&#xff0c;后台先从缓存中取数据&#xff0…

Nginx实现平滑升级

平滑升级 本篇目标&#xff1a;将现有的 nginx 1.22.0 版本升级为 1.24.0 //查看现有版本 [root12 ~]# nginx -v nginx version: nginx/1.22.01、首先在官网下载软件包&#xff0c;地址&#xff1a;nginx: download 2、把要 1.24.0 拖进 /opt 目录后&#xff0c;解压&#xf…

自动化部署证书 acme.sh 使用教程

简介 acme.sh 是一个开源的 ACME 协议的客户端工具&#xff0c;用于自动化申请、更新和部署 SSL/TLS 证书。通过使用 acme.sh&#xff0c;用户可以轻松地在服务器上设置 HTTPS 加密连接&#xff0c;而无需手动操作。它支持多种 DNS 接口和证书颁发机构&#xff0c;可以与各种 …

【MySQL面试复习】什么是聚簇索引(聚集索引)和非聚簇索引(二级索引)/什么是回表?

系列文章目录 在MySQL中&#xff0c;如何定位慢查询&#xff1f; 发现了某个SQL语句执行很慢&#xff0c;如何进行分析&#xff1f; 了解过索引吗&#xff1f;(索引的底层原理)/B 树和B树的区别是什么&#xff1f; 系列文章目录什么是聚簇索引&#xff08;聚集索引&#xff09…

无需工具清理电脑C盘

方法如下&#xff1a; 1、打开我的电脑&#xff0c;在C盘上面右键单击&#xff0c;选择属性&#xff1a; 2、然后点击清理磁盘&#xff0c;选择在自己要删掉的垃圾文件 接下来等待几分钟的样子&#xff0c;清理好就OK了&#xff0c;强迫症&#xff01;

Bert基础(四)--解码器(上)

1 理解解码器 假设我们想把英语句子I am good&#xff08;原句&#xff09;翻译成法语句子Je vais bien&#xff08;目标句&#xff09;。首先&#xff0c;将原句I am good送入编码器&#xff0c;使编码器学习原句&#xff0c;并计算特征值。在前文中&#xff0c;我们学习了编…

STM32F103学习笔记(六) RTC实时时钟(应用篇)

目录 1. RTC 实时时钟的应用场景 2. RTC 的配置与初始化 2.1 设置 RTC 时钟源 2.2 初始化 RTC 寄存器 2.3 中断配置 2.4 备份寄存器配置 2.5 校准 RTC 3. 实例演示代码 4. 总结 1. RTC 实时时钟的应用场景 实时时钟&#xff08;RTC&#xff09;在嵌入式系统中具有广泛…

2023 最新 IntelliJ IDEA 2023.3 详细配置步骤演示(图文版)<中文版>

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

【MySQL】探索表结构、数据类型和基本操作

表、记录、字段 数据库的E-R&#xff08;entity-relationship&#xff0c;实体-关系&#xff09;模型中有三个主要概念&#xff1a; 实体集 、 属性 、 关系集 。 一个实体集对应于数据库中的一个表&#xff0c;一个实体则对应于数据库表 中的一行&#xff0c;也称为一条记录。…

扫二维码播放视频的效果怎么做?如何扫码看视频?

现在经常会在很多的商品详情上发现多个二维码&#xff0c;扫码后会展现不同的内容&#xff0c;比如图片、视频、文字等等。一般产品介绍和使用说明多以视频为主&#xff0c;那么如何制作扫码播放视频的效果呢&#xff0c;相信很多小伙伴对这个制作技巧都非常的感兴趣&#xff0…