abc367 题解

第一次场切 A~F,写个题解纪念一下。
比赛链接:https://atcoder.jp/contests/abc367

A - Shout Everyday

题意:

高桥每天 \(B\) 时刻睡觉,\(C\) 时刻起床(\(B,C\) 时刻也在睡觉),请问高桥 \(A\) 时刻是否没睡。

思路:

对于 \(B<=C\)\(B>C\) 分别处理即可。

代码:

https://atcoder.jp/contests/abc367/submissions/56776201

B - Cut .0

题意:

给定一个保留三位小数的实数 \(X\),若 \(X\) 为整数,输出 \(X\),否则将 \(X\) 小数点后的 \(0\) 删去后输出。

思路:

利用 C++ 特性,可以直接输入 \(X\) 然后输出 \(X\)

代码:

https://atcoder.jp/contests/abc367/submissions/56835187

C - Enumerate Sequences

题意:

给定 \(n,k\)\(1\le n\le 8, 2\le k\le 10\)) 和一个长度为 \(n\) 的数组 \(r_i\)\(1\le r_i\le 5\)),请你按照字典序从小到大输出满足以下条件的序列:

  • 序列长度为 \(n\)
  • 序列中的每一个元素 \(a_i\),都要满足 \(a_i\le r_i\)
  • 序列中数的总和是 \(k\) 的倍数。

思路:

观察到 \(n\)\(r_i\) 都很小,考虑爆搜,枚举每一个元素该选什么,累加总和,如果元素大小是从 \(1\) 枚举到 \(r_i\),那么直接输出序列,字典序一定从小到大。

代码:

https://atcoder.jp/contests/abc367/submissions/56788422

D - Pedometer

题意:

现有一个圆环,圆环上有 \(n\)\(2\le n\le 2\times 10^5\)) 个点,第 \(i\) 个点到第 \(i+1\) 个点的距离为 \(a_i\)(我们视第 \(n+1\) 个点是第 \(1\) 个点),请求出有序数对 \((s,t)\) 满足以下要求的个数:

  • 从第 \(s\) 个点顺时针走到 \(t\) 的距离为 \(m\)\(1\le m\le 10^6\)) 的倍数。
  • \(s\neq t\)

思路:

\(S_i = \sum_{j=1}^{i - 1} a_j\),那么从 \(s\) 顺时针走到 \(t\)\(s<t\)) 的距离为 \(S_t-S_s\),那么从 \(t\) 顺时针走到 \(s\) 的距离为 \(S_{n+1}-(S_t-S_s)\)

考虑前者:

\[S_t-S_s\equiv 0 \pmod m \]

\[S_t\equiv S_s \pmod m \]

我们可以把 \(S_i\bmod m\)\(1\le i\le n\))存入桶中,然后用组合数计算相同 \(S\) 的数量。

考虑后者:

\[S_{n+1}-(S_t-S_s)\equiv 0 \pmod m \]

\[S_t\equiv S_{n+1}+S_t \pmod m \]

我们同样可以把 \(S_i\bmod m\)\(1\le i\le n\))存入桶中,但是在这里我们需要钦定 \(s<t\) 否则 \(S_t-S_s\) 就会小于 \(0\),所以我们可以在遍历 \(S_i\) 的同时计算数量,然后再将 \(S_i\bmod m\) 存入桶中。

代码:

https://atcoder.jp/contests/abc367/submissions/56809383

E - Permute K times

题意:

给定两个长度为 \(n\)\(1\le n\le 2\times 10^5\)) 的数组 \(a,x\),每次操作将 \(b_i\gets a_{x_i}\) 然后 \(a_i\gets b_i\),请问经过 \(k\)\(0\le k\le 10^{18}\)) 此操作后 \(a\) 数组的每一个数是多少。

思路:

看到 \(k\) 的范围如此之大,考虑倍增。可以发现操作 \(k\) 次,变化的只是编号,数值可以由编号求得,所以设 \(f_{i,j}\) 表示编号为 \(i\) 的数变化了 \(2^j\) 次变化成了编号为 \(f_{i,j}\) 的数,那么就有转移方程 \(\large{f_{i,j}=f_{f_{i,j-1},j-1}}\),最后枚举 \(k\) 的每一个二进制位,若是 \(1\) 就变化一次,然后输出编号所对应的数值即可。

代码:

https://atcoder.jp/contests/abc367/submissions/56815056

F - Rearrange Query

题意:

给定两个长度为 \(n\) 的数组 \(a,b\),一共有 \(q\) 次询问,每次询问由四个数 \(l_i,r_i,L_i,R_i\),如果序列 \((a_{l_i},a_{l_i+1},\cdots,a_{r_i})\)\((b_{L_i},b_{L_i+1},\cdots,b_{R_i})\) 经过重排,可以使得每一位都相同,那么输出 Yes,否则输出 No

思路:

以一下有两种思路,第一种是我自己在场上想到的思路,第二种是场下想到的思路。

主席树+哈希:

考虑将题意转化,转化为两个数组在区间内出现的数的个数相同,这可以用主席树解决,但是用普通的主席树需要枚举每一个数,算出其出现次数,然后一一比较,这样时间复杂度比暴力还高,考虑优化。我们希望的是整体比较,而不是对于每一个数进行比较,所以我们可以用到一个类似于哈希的操作,将每一个数赋予一个权值,当这个数出现,就将他所在桶(主席树)加上这个权值,然后直接判断这两个区间的总权值是否相同即可。每一个数的权值该赋多少好呢,那就随机数吧。

直接哈希:

我们发现我们想要的是区间整体比较,而不是每一个数进行比较,主席树计算区间内每一个数的出现次数时间复杂度很优,但是对于整体比较,复杂度就比直接哈希要更劣。考虑到题目中数组可以重排,我们选择用由交换律的哈希,那么我们对于每出现一个数就将其前缀的哈希值加上这个数的权值(也是随机数),那么在最后询问的时候可以直接用两个端点的哈希值一减比较是否相等即可。

代码:

posted @ 2024-08-17 22:11  liruixiong0101  阅读(18)  评论(0编辑  收藏  举报