AT ARC192D Fraction Line

结果 D 居然是 BCD 中最简单的一道吗。

首先从第一个条件入手,因为这个条件看着比第二个条件限制更严。
考虑打开 \(f\) 这个式子:\(f\left(\dfrac{S_i}{S_{i + 1}}\right) = \dfrac{S_i S_{i + 1}}{\gcd^2(S_i, S_{i + 1})} = A_i\)

接下来考虑刻画 \(\dfrac{S_i S_{i + 1}}{\gcd^2(S_i, S_{i + 1})}\),就可以与 \(A_i\) 对比得到信息。
注意到乘积和 \(\gcd\) 都是可以拆分为质数组合而成的,所以考虑分解 \(S_i = \prod\limits_{k} p_k^{e_{i, k}}(p_k\in \mathbb{P})\)
那么对于 \(p_k\) 来说,其对这个式子的贡献就是 \(\dfrac{p_k^{e_{i, k} + e_{i + 1, k}}}{p_k^{2\min\{e_{i, k}, e_{i + 1, k}\}}} = p_k^{|e_{i, k} - e_{i + 1, k}|}\)

那么此时左式被拆成了 \(p_k\) 单独考虑,对于右式 \(A_i\) 也这样做,那么分解 \(A_i = \prod\limits_{k} p_k^{c_{i, k}}\)
那么根据左式 \(=\) 右式,就应该有对于任意 \(p_k\),都有 \(\forall i\in [1, n), |e_{i, k} - e_{i + 1, k}| = c_{i, k}\)

接下来考虑第二个条件:\(\gcd\left(S_1, S_2, \cdots, S_n\right) = 1\)
因为前面已经对于了每个 \(p_k\) 拆开考虑,所以这个条件依然对于每个 \(p_k\) 考虑。
这个条件相当于是限制了对于 \(p_k\) 贡献给 \(\gcd\) 一定是 \(p_k^0 = 1\)
所以这个条件可以转化为对于任意 \(p_k\)\(\min\{e_{1, k}, e_{2, k}, \cdots, e_{n, k}\} = 0\)

因为上面的条件都是针对拆开 \(S_i\) 分析的,所以还要考虑组合有没有什么问题。
因为这题是拆分成了 \(S_i = \prod\limits_{k} p_k^{e_{i, k}}\),所以不同的 \((e_{i, 1}, e_{i, 2}, \cdots)\) 都会对应上不同的 \(S_i\)
于是根据分析,可以直接考虑对于每个 \(p_k\) 来计数,最后再组合成 \(S\)

首先考虑要组合出最终答案,每个 \(p_k\) 需要知道什么信息。
首先考虑只有 \(p_1, p_2\),答案该如何表示。
写出式子:\(\sum\limits_{e_{1\sim n, 1}}\sum\limits_{e_{1\sim n, 2}} \prod\limits_{i = 1}^n p_1^{e_{i, 1}}p_2^{e_{i, 2}} = \sum\limits_{e_{1\sim n, 1}}\sum\limits_{e_{1\sim n, 2}} \left(\prod\limits_{i = 1}^n p_1^{e_{i, 1}}\right)\times \left(\prod\limits_{i = 1}^n p_2^{e_{i, 2}}\right) = \left(\sum\limits_{e_{1\sim n, 1}} \prod\limits_{i = 1}^n p_1^{e_{i, 1}}\right)\times \left(\sum\limits_{e_{1\sim n, 2}} \prod\limits_{i = 1}^n p_2^{e_{i, 2}}\right)\)
那么这个是可以继续推广下去到 \(p_{1, 2, \cdots}\) 的。
于是可以发现对于每个 \(p_k\) 只需要知道 \(\sum\limits_{e_{1\sim n, k}} \prod\limits_{i = 1}^n p_k^{e_{i, k}}\) 的值。

那接下来就考虑如何对于每个 \(p_k\) 来统计其答案。
首先 \(c_{i, k}\) 是可以预处理出来的。
因为 \(\min\{e_{1, k}, e_{2, k}, \cdots, e_{n, k}\} = 0\),所以 \(\max\{e_{1, k}, e_{2, k}, \cdots, e_{n, k}\} \le \sum\limits_{i = 1}^{n - 1} c_{i, k}\)
发现这个 \(e_{i, k}\) 的值域不是很大,同时 DP 的时候关心 \(p_k^{e_{i, k}}\) 这个值,于是可以针对 \(e_{i, k}\) 的值设计 DP:
\(f_{i, j, 0 / 1}\) 表示 \(e_{i, k} = j\),是否存在 \(1\le i'\le i\) 使得 \(e_{i', k} = 0\)\(\sum\limits_{e_{1\sim i, k}}\prod\limits_{i' = 1}^{i} p_k^{e_{i', k}}\)
关于转移,只需要考虑 \(e_{i + 1, k} = j + c_{i, k}\)\(e_{i + 1, k} = j - c_{i, k}\) 两种情况即可,注意 \(c_{i, k} = 0\) 会算重。

对于单个 \(p_k\),DP 的复杂度是 \(\mathcal{O}\left(n\sum\limits_{i = 1}^{n - 1}c_{i, k}\right)\)
那么总的 DP 的复杂度是 \(\mathcal{O}\left(\sum\limits_{k} \left(n\sum\limits_{i = 1}^{n - 1}c_{i, k}\right)\right) = \mathcal{O}\left(n \sum\limits_{k}\sum\limits_{i = 1}^{n - 1} c_{i, k}\right)\le \mathcal{O}(n^2\log V)\)
带上预处理 \(c_{i, k}\) 的复杂度(\(n, V\) 不大随便做)的总复杂度是 \(\mathcal{O}(nV + n^2\log V)\)

#include<bits/stdc++.h>
using ll = long long;
constexpr ll mod = 998244353;
constexpr int maxn = 1e3 + 10, V = 1e3;
std::bitset<V + 1> pr;
int n, cnt[V + 1][maxn];
ll f[maxn][maxn * 11][2];
ll pw[maxn * 11];
int main() {
   for (int p = 2; p <= V; p++) {
      if (pr[p]) continue;
      for (int i = p + p; i <= V; i += p) {
         pr[i] = 1;
      }
   }
   scanf("%d", &n);
   for (int i = 1, x; i < n; i++) {
      scanf("%d", &x);
      for (int p = 2; p <= V; p++) {
         while (x % p == 0) {
            cnt[p][i]++, x /= p;
         }
      }
   }
   ll ans = 1ll;
   for (int p = 2; p <= V; p++) {
      if (pr[p]) continue;
      int *cp = cnt[p], m = 0;
      for (int i = 1; i < n; i++) m += cp[i];
      for (int c = pw[0] = 1; c <= m; c++) pw[c] = pw[c - 1] * p % mod;
      for (int i = 1; i <= n; i++) {
         for (int c = 0; c <= m; c++) {
            for (int o : {0, 1}) {
               f[i][c][o] = 0;
            }
         }
      }
      for (int c = 0; c <= m; c++) f[1][c][0]++;
      ll tot = 0;
      for (int i = 1; i <= n; i++) {
         (f[i][0][1] += f[i][0][0]) %= mod, f[i][0][0] = 0;
         for (int c = 0; c <= m; c++) {
            for (int o : {0, 1}) {
               (f[i][c][o] *= pw[c]) %= mod;
               if (i == n) {
                  (tot += f[i][c][o] * o) %= mod;
                  continue;
               }
               if (cp[i] == 0) {
                  (f[i + 1][c][o] += f[i][c][o]) %= mod;
                  continue;
               }
               if (c + cp[i] <= m) {
                  (f[i + 1][c + cp[i]][o] += f[i][c][o]) %= mod;
               }
               if (c - cp[i] >= 0) {
                  (f[i + 1][c - cp[i]][o] += f[i][c][o]) %= mod;
               }
            }
         }
      }
      (ans *= tot) %= mod;
   }
   printf("%lld\n", ans);
   return 0;
}
posted @ 2025-02-10 20:52  rizynvu  阅读(31)  评论(0)    收藏  举报