AtCoder ~~板刷~~

ARC 058

E - 和風いろはちゃん / Iroha and Haiku

题意

有一个长为 \(n\) 的序列 \(a_0,a_1,\cdots, a_{n - 1}\) ,给你三个参数 \(X,Y,Z\)

定义一个好的序列满足 存在 \(0\le x < y < z < w \le n\) 使得
\[ \begin{align} \sum_{i = x}^{y - 1} a_i &= X\\ \sum_{i = y}^{z - 1} a_i &= Y\\ \sum_{i = z}^{w - 1} a_i &= Z \end{align} \]
问满足条件的序列有多少个。(对于 \(10^9 + 7\) 取模)

\(3 \le n \le 40, 1 \le X,Z \le 5, 1 \le Y \le 7\)\(1 \le a_i \le 10, a_i \in \mathbb{N^{+}}\)

题解

一道很妙的题qwq

一开始觉得是个思博题,然后发现怎么正向计数都会算重。

后来去看了下题解,原来可以转化成 \(10^n -\) 不合法的序列数,这样就不会记重了。

但这样转化后如何记呢?数据范围十分地小,可以状压 \(dp\)

具体来说就是把一个 \(a_i\) 拆成一个 \(1\)\(a_i - 1\)\(0\)

比如 \(5\) 会被拆成 \(\underline{10000}\)

然后我们就可以把之前填的数顺次拼起来了。

这样有什么好处呢?不难发现如果一段连续的和为 \(S\) ,那么 \(S\) 转化后的集合 会是 连续一段转化后拼起来构成的集合的 子集

比如 \(2 + 4 = 6\) ,就有 \(\underline {100000} \in \underline{10} + \underline{1000} = \underline{101000}\)

那么我们只要对于每个位置状压前 \(X + Y + Z = 17\) 位就行了,一开始 \(X,Y,Z\) 压成的状态顺次拼到一起的状态,就是所有不可行的状态的自己。

枚举当前填到哪一位,以及状态,再枚举这位填什么就行了,复杂度就是 \(O(10n2^{X+Y+Z})\) 的。

代码

戳这个 链接 ,好写的很。

ARC 059

F - バイナリハック / Unhappy Hacking

题意

一开始会有个空串 \(S\) ,有三个操作。

  • \(S\) 后面填个 \(0\)
  • \(S\) 后面填个 \(1\)
  • 删去 \(S\) 的最后一个字符,如果 \(S\) 为空,那么不会改变。

然后你会进行 \(n\) 次操作,给你最后的串 \(S\) ,问有多少种不同的操作序列满足条件。(对于 \(10^9 + 7\) 取模)

\(n \le 5000, 1 \le |S| \le n\)

题解

一开始随便想了个 \(O(n^3)\) 的暴力,就是令 dp[i][j][k] 为当前进行了 \(i\) 次操作,串长为 \(j\) ,第一个失配的地方在 \(k\) 的操作方案数,对于当前进行什么操作分开考虑就行了。

其实正解很思博,我们之前那个 dp 第三维是没有必要的,因为我们发现串的形态是不会影响答案的,所以就令 dp[i][j] 为进行了 \(i\) 次操作,串长为 \(j\) 的方案数。

最后答案就是 \(\displaystyle \frac{dp[n][len]}{2^{len}}\) ,因为最后每个串对应的方案数都是一样的,总共有 \(2^{len}\) 个串,这样就是 \(O(n ^ 2)\) 的了。

其实可以继续优化,怎么考虑计数呢,因为最后的串长要恰好为 \(len\) ,我们可以转化成至多为 \(len\) 的答案减去至多为 \(len - 1\) 的答案。

我们假设 \(f(x)\) 为串长至少为 \(x\) 的答案,那么表达出来就是:
\[ f(x) = \sum_{i = 0}^{n} [i - (n - i) \le x] ({n \choose i} - {n \choose i - (x + 1)}) \times 2^{i} \]
也就是我们考虑在 \(n\) 个操作中有 \(i\) 个操作为在后面添加字符,剩余 \(n - i\) 个操作为退格操作。

  • \([i - (n - i) \le x]\) 意味着所有退格和添加字符操作 全部抵消 后串长不超过 \(x\) ,这是必要的条件。

  • \(\displaystyle {n \choose i}\) 是所有可能添加和退格操作的排列,\(-\displaystyle {n \choose i - (x + 1)}\) 是所有最后串长会超过 \(x\) 的情况。

    为什么会出现超过 \(x\) 的情况呢?因为会有好一些退格操作都不会产生作用,不会产生作用的如果有 \(i - (x + 1)\) 及以上个,那么就是不行的。

    不难发现,把其中不会消除的 \(i - (x + 1)\) 退格操作放在排列在 \(n\) 个总操作之中的任意一个地方,对应仅对应且仅对应一组不合法的解。

  • 最后发现每个添加数字的操作会对应两个操作,所以还要乘上 \(2^i\)

预处理了阶乘和阶乘逆元后就可以做到 \(O(n)\) 的复杂度啦。

代码

\(O(n^3):\) 代码戳这里

\(O(n^2):\) 代码戳这里

\(O(n):\) 代码戳这里

猜你喜欢

转载自www.cnblogs.com/zjp-shadow/p/9851787.html