0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

解きます

解く

式は一瞬で立ちますね

$$f = \prod_{k=1}^N \frac{1-x^{k\left(A_k+1\right)}}{1-x^k}$$

maspyさんの記事に書いてあるテクが使えそうです.

$$\begin{align}
f &= \exp\sum_{k=1}^N\log\frac{1-x^{k\left(A_k+1\right)}}{1-x^k} \\
&= \exp\sum_{k=1}^N\log\left(1-x^{k\left(A_k+1\right)}\right)-\log\left(1-x^k\right) \\
&= \exp\int\left(\sum_{k=1}^N\frac{-k\left(A_k+1\right)x^{k\left(A_k+1\right)-1}}{1-x^{k\left(A_k+1\right)}}-\frac{-kx^{k-1}}{1-x^k}\right)\mathrm dx \\
\end{align}$$
分数の羃の肩を見ると, みんな$k$とかついているため, 項数は$k$に反比例して減っていきます. $N$次以下の項は全体で$O\left(N\log N\right)$個しかないと言え, これを愚直に全て足してシグマは計算できます.

あとは指数関数が計算できればよいですが, これは$\log f-g=0$みたいな方程式をニュートン法で解けばよいです:
$$\begin{align}
f_{n+1}&=f_n-\frac{\log f_n-g}{\left(\log f_n-g\right)'} \\
&=f_n-\frac{\log f_n-g}{1/f_n} \\
&=f_n\left(1-\log f_n+g\right) \\
\end{align}$$

use ac_library::*;
use proconio::*;

type Mint = ModInt998244353;

fn main() {
    input! {
        n: usize,
        a: [usize; n],
    }
    // シグマ
    let mut s = vec![Mint::raw(0); n.next_power_of_two() - 1];
    for k in 1..=n {
        let g = k * (a[k - 1] + 1);
        // 左側の分数
        if g - 1 < s.len() {
            for v in s[g - 1..].iter_mut().step_by(g) {
                *v -= g;
            }
        }
        // 右側の分数
        for v in s[k - 1..].iter_mut().step_by(k) {
            *v += k;
        }
    }
    // 積分する
    s.insert(0, Mint::raw(0));
    for (i, v) in s.iter_mut().enumerate().skip(1) {
        *v /= i;
    }
    // 指数関数をニュートン法で計算する
    // 答え
    let mut exp = vec![Mint::raw(1)];
    // expの逆数
    let mut inv_exp = vec![Mint::raw(1)];
    // 十分な精度になるまで反復
    while exp.len() < s.len() {
        // 仮でinv_expのニュートン法をすすめる
        {
            let m = convolution(&inv_exp, &inv_exp);
            let m = convolution(&m, &exp);
            inv_exp.extend((0..inv_exp.len() - 1).map(|_| Mint::raw(0)));
            for i in 0..inv_exp.len() {
                inv_exp[i] = inv_exp[i] * 2 - m[i];
            }
        }
        // 答えの微分 d/dx[exp s]
        let dexp = exp
            .iter()
            .enumerate()
            .skip(1)
            .map(|(i, v)| *v * i)
            .collect::<Vec<_>>();
        // (log f)'
        let mut p = convolution(&inv_exp, &dexp);
        // 積分する
        p.insert(0, Mint::raw(0));
        for (i, v) in p.iter_mut().enumerate().skip(1) {
            *v /= i;
        }
        // 1 - log f + s
        let mut q = vec![Mint::raw(0); exp.len() * 2];
        for (i, v) in q.iter_mut().enumerate() {
            *v = s[i] - p.get(i).unwrap_or(&Mint::raw(0));
        }
        q[0] += 1;
        exp = convolution(&exp, &q);
        // 精度が無い部分を切り捨て
        exp.drain(q.len()..);
        // expを変更したのでinv_expも再計算する
        {
            inv_exp.drain(exp.len() / 2..);
            let m = convolution(&inv_exp, &inv_exp);
            let m = convolution(&m, &exp);
            inv_exp.extend((0..inv_exp.len()).map(|_| Mint::raw(0)));
            for i in 0..inv_exp.len() {
                inv_exp[i] = inv_exp[i] * 2 - m[i];
            }
        }
    }
    println!("{}", exp[n]);
}

提出(472 ms):

終わり

デバッグ出力を消し忘れて1WA出しました
以上です

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?