ABC372 F 题解

news/2024/9/22 20:39:27

F - Teleporting Takahashi 2

先把问题转化一下:把环断开成链,复制 \((K + 1)\) 层,每走一步就相当于前进一层:

可以想到一个简单的 dp:设 \(f(i, j)\) 表示走到第 \(i\) 层第 \(j\) 个位置的方案数。

  • 初始化:\(f(0, 1) = 1\),其它均为 \(0\),表示 Takahashi 从第 \(0\) 层的 \(1\) 位置出发。
  • 答案统计:\(ans = \sum_{i = 1}^{N} f(K + 1, i)\)
  • 转移:\(f(i, j) = \sum_{v \in pre(j)} f(i - 1, v)\),其中 \(pre(j)\) 能通过一条边直接到达 \(j\) 的点的集合。

上述做法的时空复杂度都是 \(O(NK)\)。由于每层的状态只和前一层有关,我们可以简单地用滚动数组把空间复杂度优化到 \(O(N)\),但时间复杂度似乎不太好优化。(提交记录)

(下面为了方便,把点的编号转为从 \(0\) 开始。实际上,对于环上的问题,0-indexed 往往都更方便。)

突破口在于 \(M\)。我们先假设 \(M = 0\)。这时,所有的边都形如 \((i, i + 1)\)(在环的意义下),并且所有的点 \(j\) 都只能从前一层的 \(j-1\) 这一个位置转移过来,也就是 \(f(i, j) = f(i-1, j-1)\)。换句话说,我们把 \(f(i - 1, *)\) ”右移“一位就得到了 \(f(i, *)\)

这启示我们转移时,不用暴力地赋值 \(f(i, *)\),而是用一个变量 \(be\) 代表当前数组把哪个下标当作“\(1\)”,每次转移到下一层,就让 \(be \gets (be - 1) \bmod N\) (也就是在环上自减 \(1\))。用 \(f'\) 表示代码中的数组:一开始在第 \(0\) 层,\(be = 1\),于是 \(f'(1) = f(0, 1), f'(2) = f(0, 2), \dots, f'(N) = f(0, N)\)。转移到第 \(1\) 层以后,\(be = N\),于是 \(f'(N) = f(1, 1), f'(1) = f(1, 2), \dots, f'(N-1) = f(N)\)。这样,转移时我们只需更新 \(be\),而不用把 \(f'\) 全部扫一遍。

\(M \not= 0\) 时呢?我们注意到,只有 \(M\) 条边不是 \((i, i+1)\) 类型的,而 \(M \le 50\),因此可以暴力地枚举这些边来转移。

具体实现时,下标转化的细节有点多。此外,为了防止新旧版本的 \(f'\) 混淆,我用了 map 来存储那些被 \(M\) 条边连接的点的值。这使得时间复杂度乘上一个 \(\log\),或许更精细的做法可以去掉这个 \(\log\),但我感觉用 map 方便一些。

时间复杂度 \(O(N + KM \log M)\),空间复杂度 \(O(N + M)\)

参考代码:

vector<int> f(N);
f[0] = 1;
int be = 0;
map<int, int> tmp;
for(int i = 1; i <= K; i++)
{tmp.clear();be = (be + N - 1) % N;for(auto ed: e){int u = ed.u, v = ed.v;u = (be + 1 + u) % N, v = (be + v) % N;if(tmp.find(v) == tmp.end()) tmp[v] = f[v];tmp[v] = (f[u] + tmp[v]) % MOD;}for(auto p: tmp)f[p.first] = p.second;
}int ans = 0;
for(int x: f)ans = (ans + x) % MOD;
cout << ans << endl;

提交记录

(注:图源:ATcoder 的官方题解)

G - Ax + By < C

咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕

while(1) printf("gugugu");

I can't solve this problem by myself.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

【做题笔记】收集邮票 做题笔记

水。P4550 收集邮票展开目录 目录P4550 收集邮票ReadingStep 1Step 2Code彩蛋Reading \(k\ge 1\) 时,可以通过支付 \(k\) 元钱获得一张 \(n\) 种邮票中的某种邮票。这 \(n\) 种邮票等概率出现,求买到全部 \(n\) 种邮票的花费期望。 Step 1 \(k\) 次 \(k\) 元太难搞了,干脆直…

单机版 ClickHouse 部署和 SpringBoot 程序访问

ClickHouse 是俄罗斯的 Yandex 于 2016 年开源的列式存储数据库(DBMS),使用C++语言编写,主要用于在线分析处理查询(OLAP),能够使用SQL查询实时生成分析数据报告。 OLAP 为联机分析处理,专注于统计查询;OLTP 为联机事务处理,专注于增删改。 ClickHouse 的优势在于单表…

用户验收测试指南8实施测试

8 实施测试 到目前为止,我们已经规划了我们的 UAT 演习,并制定了测试的总体战略,然后设计了所有测试并编写了测试脚本。现在,我们已准备好实施计划和进行测试。 在本章中,我们将介绍如何安排所有测试,以实现我们的测试策略,并根据验收标准评估系统。为此,我们需要记录所…

Linux中删除文本中所有的重复的字符保持唯一

001、[root@PC1 test]# ls a.txt [root@PC1 test]# cat a.txt ## 测试文本 abk akkkkccc 8777 ,,, aaaf 333444 --- uukk22 [root@PC1 test]# cat a.txt | tr -s [:alnum:] ## 删除连续的重复字符 abk akc 87 ,,, af 34 --- uk2 [root@PC1 test]# …

ConcurrentLinkedQueue详解(图文并茂)

前言 ConcurrentLinkedQueue是基于链接节点的无界线程安全队列。此队列按照FIFO(先进先出)原则对元素进行排序。队列的头部是队列中存在时间最长的元素,而队列的尾部则是最近添加的元素。新的元素总是被插入到队列的尾部,而队列的获取操作(例如poll或peek)则是从队列头部…

Linux 中实现文本中所有的单词的第一个字符大写,其余字符小写

001、[root@PC1 test]# ls a.txt [root@PC1 test]# cat a.txt ## 测试数据 afdf eDET FDSS FFde fexk mxnd [root@PC1 test]# cat a.txt | awk {for(i = 1; i <= NF; i++) {$i = toupper(subst…

Docker方式搭建Maven私服

私服搭建 如下讲解如何基于Docker方式快速搭建Nexus3私服。 编写docker-compose.yaml文件,内容如下: version: 2services:nexus3:image: sonatype/nexus3:3.72.0container_name: nexus3restart: alwaysports:- 8081:8081 volumes:- /data/opt/nexus3/data:/nexus-data为了避免…

安全的路很长,致迷茫的你

最近有一些朋友找到我,跟我聊,说自己感觉很迷茫,不知所措,不知道未来该怎么办?安全该怎么做?OKR该怎么写?其实我想反问他以下几个问题: 1.漏洞研究了几个? 2.样本分析了几个? 3.这段时间看了多少安全技术类文档? 4.目前流行的恶意样本家族都有哪些? 5.目当流行的影…