1
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?

解きます

解く

一旦$m$を固定した状態で解きます. 求めるべきものは
$$f_m := \prod_{k=m}^{m+L-1}\frac 1{1-x^k}$$
としたとき$\left[x^N\right]f_m$ですね. 愚直にやれば$O(NL)$で求められます.
ただ, これを$M-L+1$回求める必要があり, これを毎回行っていては時間がかかりすぎます.

どうするかというと, 一旦$f_{m+1}/f_m$を計算してみます.
$$\begin{align}
\frac{f_{m+1}}{f_m}
&= \frac{\prod_{k=m+1}^{m+L}\frac 1{1-x^k}}{\prod_{k=m}^{m+L-1}\frac 1{1-x^k}} \\
&= \frac{\prod_{k=m}^{m+L-1}1-x^k}{\prod_{k=m+1}^{m+L}1-x^k} \\
&= \frac{\left(1-x^m\right)\left(1-x^{m+1}\right)\cdots\left(1-x^{m+L-2}\right)\left(1-x^{m+L-1}\right)}{\left(1-x^{m+1}\right)\left(1-x^{m+2}\right)\cdots\left(1-x^{m+L-1}\right)\left(1-x^{m+L}\right)} \\
&= \frac{\left(1-x^m\right)\cancel{\left(1-x^{m+1}\right)}\cdots\cancel{\left(1-x^{m+L-2}\right)}\cancel{\left(1-x^{m+L-1}\right)}}{\cancel{\left(1-x^{m+1}\right)}\cancel{\left(1-x^{m+2}\right)}\cdots\cancel{\left(1-x^{m+L-1}\right)}\left(1-x^{m+L}\right)} \\
&= \frac{1-x^m}{1-x^{m+L}}
\end{align}$$
大部分が共通してるので打ち消してこうなりました. つまり
$$f_{m+1}=\frac{1-x^m}{1-x^{m+L}} f_m$$
なので, 計算結果を$1-x^{m+L}$で割って$1-x^m$を掛けたら$m$が1だけ大きい結果が得られる, ということです. これにかかるコストは$O\left(N\right)$なので, $f_1$を愚直に求めたあとこれを繰り返して他の結果を得るようにすれば全体の計算量が$O\left(N M\right)$になります.

FPSという視点から離れて操作を見ると「$1-x^{m+L}$で割る」は「$m+L$円硬貨を使えるようにする」に, 「$1-x^m$を掛ける」は「$m$円硬貨を使えなくする」にそれぞれ対応します.

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

type Mint = ModInt998244353;

fn main() {
    input! {
        n: usize,
        m: usize,
        l: usize,
    }
    // fpsを定数関数1で初期化
    let mut fps = vec![Mint::raw(0); n + 1];
    fps[0] = Mint::raw(1);
    // f_1を求める
    for k in 1..=l {
        // 1-x^k で割る
        for i in k..=n {
            let temp = fps[i - k];
            fps[i] += temp;
        }
    }
    // f_1が求まったので, n次の係数を出力
    println!("{}", fps[n]);
    for m in 1..m - l + 1 {
        // 1-x^(m+l) で割る
        for i in m + l..=n {
            let temp = fps[i - m - l];
            fps[i] += temp;
        }
        // 1-x^m を掛ける
        for i in (m..=n).rev() {
            let temp = fps[i - m];
            fps[i] -= temp;
        }
        // f_(m+1)が求まったので, n次の係数を出力
        println!("{}", fps[n]);
    }
}

提出(34 ms):

終わり

数式弄りも頭の片隅で計算量を意識してやりましょうね
以上です

1
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
1
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?