#include #include using namespace std; using namespace atcoder; using ll = long long; using mint = modint998244353; // using mint = modint1000000007; template using vec = vector; template using pr = pair; template using mipq = priority_queue, greater>; #define overload4(_1, _2, _3, _4, name, ...) name #define rep1(i, n) for (auto i = decay_t{}; (i) < (n); ++(i)) #define rep2(i, l, r) for (auto i = (l); (i) < (r); ++(i)) #define rep3(i, l, r, d) for (auto i = (l); (i) < (r); i += (d)) #define rep(...) overload4(__VA_ARGS__, rep3, rep2, rep1)(__VA_ARGS__) #define rrep(i, r, l) for (int i = (r); i >= (l); --i) template bool chmax(T &a, const T b) { return (a < b ? a = b, true : false); } template bool chmin(T &a, const T b) { return (a > b ? a = b, true : false); } constexpr int INF = 1 << 30; constexpr ll LINF = 1LL << 60; void solve(); int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout << fixed << setprecision(15); int T = 1; // cin >> T; while (T--) solve(); } template struct SWAG { vec front, back, cumf, cumb; SWAG() {} void push_back(S x) { back.emplace_back(x); cumb.emplace_back((cumb.empty() ? x : op(cumb.back(), x))); } void push_front(S x) { front.emplace_back(x); cumf.emplace_back((cumf.empty() ? x : op(x, cumf.back()))); } void init(vec dat) { front.clear(); back.clear(); cumf.clear(); cumb.clear(); int n = dat.size(); rrep(i, n / 2 - 1, 0) push_front(dat[i]); rep(i, n / 2, n) push_back(dat[i]); } void pop_front() { if (front.empty()) { assert(!back.empty()); int n = back.size(); vec dat(n - 1); rep(i, 1, n) dat[i - 1] = back[i]; init(dat); } else { front.pop_back(); cumf.pop_back(); if (front.empty()) { init(back); } } } void pop_back() { if (back.empty()) { assert(!front.empty()); int n = front.size(); vec dat(n - 1); rep(i, n - 1) dat[i] = front[n - 1 - i]; init(dat); } else { back.pop_back(); cumb.pop_back(); if (back.empty()) { ranges::reverse(front); init(front); } } } void fold() { return (cumf.empty() ? cumb.back() : (cumb.empty() ? cumf.back() : op(cumf.back(), cumb.back()))); } }; struct S { int x; vec val; }; int K; S op(S a, S b) { if (a.x > b.x) swap(a, b); assert(b.x != -1); S res; res.x = -1; res.val = a.val; rep(i, K) res.val[(i + b.x) % K] += a.val[i]; return res; }; void solve() { int N, M; cin >> N >> M >> K; SWAG s; auto get = [&] { if (s.cumf.empty()) return s.cumb.back().val[0]; else if (s.cumb.empty()) return s.cumf.back().val[0]; mint res = 0; rep(i, K) res += s.cumf.back().val[i] * s.cumb.back().val[(K - i) % K]; return res; }; rep(i, N) { int a; cin >> a; vec val(K); val[0] = 1; val[a] += 1; s.push_back({a, val}); if (M - 1 <= i) { cout << (get() - 1).val() << '\n'; s.pop_front(); } } }