結果

問題 No.3447 Power Projection(constant)
コンテスト
ユーザー Naru820
提出日時 2026-02-20 21:40:37
言語 C++23
(gcc 15.2.0 + boost 1.89.0)
結果
AC  
実行時間 2 ms / 2,000 ms
コード長 17,014 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 8,582 ms
コンパイル使用メモリ 410,224 KB
実行使用メモリ 7,976 KB
最終ジャッジ日時 2026-02-20 21:40:48
合計ジャッジ時間 10,306 ms
ジャッジサーバーID
(参考情報)
judge1 / judge2
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other AC * 22
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include<bits/stdc++.h>
#include<atcoder/all>
#define fast std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout.tie(nullptr)
#define eb emplace_back
#define all(x) (x).begin(), (x).end()
using namespace std;
using namespace atcoder;
using ll = long long;
using mint = atcoder::modint998244353;
constexpr ll inf = 2e18;
constexpr ll mod = 998244353;

static void judge(bool c) {
    std::cout << (c ? "Yes" : "No") << '\n';
}

static vector<mint> trim(vector<mint>& a){ while(!a.empty() && a.back()==mint(0)) a.pop_back(); return a; }
vector<mint> operator*(const vector<mint>& a,const vector<mint>& b){
    if(a.empty()||b.empty()) return {};
    auto c = convolution(a,b);
    return c;
}
vector<mint> prod(const vector<mint> &f,const vector<mint> &g){ return f*g; }

static vector<mint> mul_trunc(const vector<mint>& a,const vector<mint>& b,int n){
    if(a.empty()||b.empty()) return vector<mint>();
    int need = min<int>(n+1,(int)a.size()+(int)b.size()-1);
    auto c=convolution(a,b);
    c.resize(need);
    return c;
}

static vector<mint> poly_inv(const vector<mint>& a,int n){
    if(a.empty() || a[0]==mint(0)) throw runtime_error("poly_inv: bad input");
    vector<mint> r(1, a[0].inv());
    int m = 1;
    vector<mint> two_minus_t,as;
    while(m <= n){
        int cur = m<<1;
        as.assign(min((int)a.size(), cur),mint(0));
        for(int i=0;i<(int)as.size();++i) as[i]=a[i];
        auto t = mul_trunc(r, as, cur-1);
        two_minus_t.assign(cur, mint(0));
        two_minus_t[0] = mint(2) - (t.size()>0? t[0] : mint(0));
        for(int i=1;i<cur;i++){
            mint ti = (i < (int)t.size() ? t[i] : mint(0));
            two_minus_t[i] = -ti;
        }
        r = mul_trunc(r, two_minus_t, cur-1);
        r.resize(cur);
        m = cur;
    }
    r.resize(n+1);
    return r;
}

vector<mint> div(const vector<mint> &f,const vector<mint> &g,int n){
    if(g.empty()) throw runtime_error("div: g is zero");
    if(g[0]==mint(0)) throw runtime_error("div: g[0]==0");
    int need = n+1;
    vector<mint> ig = poly_inv(g, n);
    auto res = mul_trunc(f, ig, n);
    res.resize(need);
    return res;
}

static vector<mint> derivative(const vector<mint>& a){
    if(a.size()<=1) return vector<mint>();
    vector<mint> r(a.size()-1);
    for(size_t i=1;i<a.size();++i) r[i-1]=a[i]*mint((ll)i);
    return r;
}

static vector<mint> integral(const vector<mint>& a){
    vector<mint> r(a.size()+1);
    r[0]=mint(0);
    for(size_t i=0;i<a.size();++i) r[i+1]=a[i]/mint((ll)(i+1));
    return r;
}

vector<mint> log(const vector<mint> &f,int n){
    if(f.empty()||f[0]!=mint(1)) throw runtime_error("log: constant term must be 1");
    auto df = derivative(f);
    auto invf = poly_inv(f, n);
    auto mul = mul_trunc(df, invf, max(0,n-1));
    auto res = ::integral(mul);
    res.resize(n+1);
    return res;
}

vector<mint> exp(const vector<mint> &f,int n){
    if(f.empty()||f[0]!=mint(0)) throw runtime_error("exp: constant term must be 0");
    vector<mint> g(1,mint(1));
    int m=1;
    while(m<=n){
        int cur = m<<1;
        int need = min(cur, n+1);
        vector<mint> ln = log(g, need-1);
        vector<mint> diff(need);
        for(int i=0;i<need;i++){
            mint fi = (i < (int)f.size() ? f[i] : mint(0));
            mint lni = (i < (int)ln.size() ? ln[i] : mint(0));
            diff[i] = fi - lni;
        }
        diff[0] = diff[0] + mint(1);
        g = mul_trunc(g, diff, need-1);
        g.resize(need);
        m = cur;
    }
    g.resize(n+1);
    return g;
}

vector<mint> composition(const vector<mint> &f,const vector<mint> &g,int n){
    if(g.empty() || g[0]!=mint(0)) throw runtime_error("composition: g[0] must be 0");
    int degf = (int)f.size();
    vector<mint> res(1,mint(0));
    for(int i=degf-1;i>=0;--i){
        res = mul_trunc(res, g, n);
        if((int)res.size()>n+1) res.resize(n+1);
        if((int)res.size()<n+1) res.resize(n+1,mint(0));
        res[0] += f[i];
    }
    res.resize(n+1);
    return res;
}

vector<mint> inv(const vector<mint> &f,int n){
    if(f.empty()) throw runtime_error("inv composition: empty");
    if(f[0]!=mint(0)) throw runtime_error("inv composition: constant term must be 0");
    if(f.size()<=1 || f[1]==mint(0)) throw runtime_error("inv composition: linear coeff must be nonzero");
    vector<mint> g(1,mint(0));
    int m=1;
    while(m<=n){
        int cur = m<<1;
        int need = min(cur, n+1);
        auto fg = composition(f, g, need-1);
        vector<mint> delta(need);
        for(int i=0;i<need;i++){
            mint val = (i==1? mint(1) : mint(0));
            mint fgc = (i < (int)fg.size() ? fg[i] : mint(0));
            delta[i] = fgc - val;
        }
        auto fprime = derivative(f);
        auto fprimg = composition(fprime, g, need-1);
        auto invfprimg = poly_inv(fprimg, need-1);
        auto correction = mul_trunc(delta, invfprimg, need-1);
        g.resize(need);
        for(int i=0;i<need;i++){
            mint gi = (i < (int)g.size() ? g[i] : mint(0));
            mint corr = (i < (int)correction.size() ? correction[i] : mint(0));
            g[i] = gi - corr;
        }
        m = cur;
    }
    g.resize(n+1);
    return g;
}
static size_t ceil2(size_t n){
    size_t p = 1;
    while(p < n) p <<= 1;
    return p;
}

static vector<mint> poly_mod(vector<mint> f, vector<mint> g){
    f = trim(f);
    g = trim(g);
    if(g.empty()) throw runtime_error("poly_mod: g empty");
    
    if(f.size() < g.size()) return f;

    int n = (int)f.size() - 1;
    int m = (int)g.size() - 1;
    int qdeg = n - m; 

    vector<mint> f_rev = f;
    reverse(all(f_rev));
    vector<mint> g_rev = g;
    reverse(all(g_rev));
    int need = qdeg + 1;
    f_rev.resize(need);
    g_rev.resize(need);

    auto inv_g_rev = poly_inv(g_rev, qdeg);
    auto q_rev = mul_trunc(f_rev, inv_g_rev, qdeg);
    q_rev.resize(need);

    vector<mint> q = q_rev;
    reverse(all(q)); 
    q = trim(q);

    auto qg = prod(q, g);
    
    int rem_size = (int)g.size() - 1;
    if (rem_size < 0) rem_size = 0;
    vector<mint> r(rem_size);

    for(int i = 0; i < rem_size; i++) {
        mint fi = (i < (int)f.size() ? f[i] : mint(0));
        mint qgi = (i < (int)qg.size() ? qg[i] : mint(0));
        r[i] = fi - qgi;
    }
    
    return trim(r);
}

vector<mint> multipoint_eval(const vector<mint> &a, const vector<int> &point){
    size_t m = point.size();
    if(m == 0) return vector<mint>();
    size_t m2 = ceil2(m);
    vector<vector<mint>> g(m2 + m2, vector<mint>(1, mint(1)));
    for(size_t i=0;i<m;i++){
        mint xi = mint((long long)point[i]);
        g[m2 + i] = vector<mint>{-xi, mint(1)}; 
    }
    for(size_t i = m2; i-- > 1; ){
        g[i] = prod(g[i<<1], g[i<<1|1]);
    }

    g[1] = poly_mod(a, g[1]);
    for(size_t i = 2; i < m2 + m; ++i){
        g[i] = poly_mod(g[i>>1], g[i]);
    }
    vector<mint> ys(m);
    for(size_t i=0;i<m;i++){
        ys[i] = (g[m2 + i].empty() ? mint(0) : g[m2 + i][0]);
    }
    return ys;
}

class BinomialCoefficient {
private:
    long long mod;
    std::vector<long long> fact;
    std::vector<long long> inv_fact;

    long long power(long long base, long long exp) {
        long long res = 1;
        base %= mod;
        while (exp > 0) {
            if (exp % 2 == 1) res = (res * base) % mod;
            base = (base * base) % mod;
            exp /= 2;
        }
        return res;
    }

public:
    BinomialCoefficient(int n_max, long long m) : mod(m) {
        fact.resize(n_max + 1);
        inv_fact.resize(n_max + 1);

        fact[0] = 1;
        inv_fact[0] = 1;

        for (int i = 1; i <= n_max; ++i) {
            fact[i] = (fact[i - 1] * i) % mod;
        }

        inv_fact[n_max] = power(fact[n_max], mod - 2);

        for (int i = n_max; i > 0; --i) {
            inv_fact[i - 1] = (inv_fact[i] * i) % mod;
        }
    }

    long long com(int n, int r) {
        if (r < 0 || n < r) {
            return 0;
        }
        if (static_cast<size_t>(n) >= fact.size()) {
            return -1;
        }
        long long result = fact[n];
        result = (result * inv_fact[r]) % mod;
        result = (result * inv_fact[n - r]) % mod;
        return result;
    }
};

vector<mint> power(const vector<mint> &f, long long e, int n) {
    if (f.empty()) return vector<mint>(n + 1, 0);
    if (e == 0) {
        vector<mint> res(n + 1, 0);
        res[0] = 1;
        return res;
    }
    int shift = 0;
    while (shift < (int)f.size() && f[shift] == mint(0)) shift++;
    if (shift == (int)f.size()) return vector<mint>(n + 1, 0);
    if (e > 0 && shift > (n / e)) return vector<mint>(n + 1, 0);
    vector<mint> g;
    g.reserve(f.size() - shift);
    for (int i = shift; i < (int)f.size(); ++i) g.push_back(f[i]);
    mint c = g[0];
    mint inv_c = c.inv();
    for (auto& x : g) x *= inv_c;
    auto logg = log(g, n);
    for (auto& x : logg) x *= mint(e);
    auto expg = exp(logg, n);
    mint c_pow = c.pow(e);
    for (auto& x : expg) x *= c_pow;
    vector<mint> res(n + 1, 0);
    int total_shift = (int)(e * shift);
    for (int i = 0; i < (int)expg.size(); ++i) {
        if (total_shift + i <= n) res[total_shift + i] = expg[i];
    }
    return res;
}
vector<mint> get_power_sums(const vector<ll>& arr, int k_max) {
    int n = arr.size();
    if (n == 0) {
        return vector<mint>(k_max + 1, 0);
    }
    function<vector<mint>(int, int)> dc_prod = 
        [&](int l, int r) -> vector<mint> {
        if (l == r) {
            return {1, -mint(arr[l])};
        }
        int mid = (l + r) / 2;
        auto left = dc_prod(l, mid);
        auto right = dc_prod(mid + 1, r);
        return prod(left, right);
    };
    vector<mint> Q = dc_prod(0, n - 1);
    vector<mint> dQ = derivative(Q);
    vector<mint> invQ = poly_inv(Q, k_max);
    vector<mint> R = mul_trunc(dQ, invQ, k_max);
    R.resize(k_max + 1, 0); 
    vector<mint> P_sum(k_max + 1);
    P_sum[0] = n;
    for (int i = 1; i <= k_max; ++i) {
        P_sum[i] = -R[i - 1];
    }
    return P_sum;
}

mint bostan_mori(vector<mint> f, vector<mint> g, ll n) {
    f = trim(f);
    g = trim(g);
    if (g.empty() || g[0] == mint(0)) throw runtime_error("bostan_mori: bad denominator");
    
    while (n > 0) {
        auto g_neg = g;
        for (size_t i = 1; i < g_neg.size(); i += 2) g_neg[i] = -g_neg[i];
        
        auto g_sq = convolution(g, g_neg);
        auto f_gneg = convolution(f, g_neg);

        size_t g_sz = (g_sq.size() + 1) >> 1;
        g.resize(g_sz);
        for (size_t i = 0; i < g_sz; ++i) {
            g[i] = (2 * i < g_sq.size() ? g_sq[2 * i] : mint(0));
        }

        size_t f_sz = (f_gneg.size() + (n & 1) + 1) >> 1;
        f.resize(f_sz);
        int parity = (n & 1);
        for (size_t i = 0; i < f_sz; ++i) {
            size_t idx = 2 * i + parity;
            f[i] = (idx < f_gneg.size() ? f_gneg[idx] : mint(0));
        }

        n >>= 1;
    }
    
    return f.empty() ? mint(0) : f[0] * g[0].inv();
}

namespace fps_internal {
    vector<vector<mint>> precompute_powers(const vector<mint>& g, int n, int k) {
        vector<vector<mint>> powers;
        powers.reserve(32);
        powers.push_back(g); 
        
        int deg = 1;
        while (deg < k) {
            auto next_g = mul_trunc(powers.back(), powers.back(), n);
            powers.push_back(next_g);
            deg <<= 1;
        }
        return powers;
    }

    vector<mint> compose_dc(const vector<mint>& f, int l, int r, 
                            const vector<vector<mint>>& g_powers, int level, int n) {
        if (l + 1 == r) {
            if (l < (int)f.size()) return {f[l]};
            return {mint(0)};
        }
        
        int mid = (l + r) >> 1;
        auto h_left = compose_dc(f, l, mid, g_powers, level - 1, n);
        auto h_right = compose_dc(f, mid, r, g_powers, level - 1, n);
        auto rhs = mul_trunc(h_right, g_powers[level - 1], n);
        
        if (h_left.size() < rhs.size()) h_left.resize(rhs.size(), mint(0));
        for (size_t i = 0; i < rhs.size(); ++i) h_left[i] += rhs[i];
        
        return h_left;
    }
}

vector<mint> compose(const vector<mint>& f, const vector<mint>& g, int n) {
    if (f.empty()) return {};
    if (g.empty()) return {f[0]}; 
    int deg_f = (int)f.size() - 1;
    if (deg_f == 0) return {f[0]};

    int k = 1;
    int level = 0;
    while (k <= deg_f) {
        k <<= 1;
        level++;
    }
    auto g_powers = fps_internal::precompute_powers(g, n, k);
    
    return fps_internal::compose_dc(f, 0, k, g_powers, level, n);
}

vector<mint> inverse(const vector<mint>& f, int n) {
    if (f.empty() || f[0] != mint(0)) throw runtime_error("inverse: constant term must be 0");
    if (f.size() <= 1 || f[1] == mint(0)) throw runtime_error("inverse: linear coeff must be nonzero");
    vector<mint> g = {mint(0)}; 
    g = {mint(0), f[1].inv()};
    
    int m = 1;
    while (m <= n) {
        int cur = m << 1;
        int need = min(cur, n + 1);
        auto fg = compose(f, g, need - 1);
        if (fg.size() > 1) fg[1] -= mint(1);
        
        auto f_prime = derivative(f);
        auto fpg = compose(f_prime, g, need - 1);
        auto inv_fpg = poly_inv(fpg, need - 1);
        
        auto correction = mul_trunc(fg, inv_fpg, need - 1);
        
        g.resize(need);
        for (int i = 0; i < need; ++i) {
            if (i < (int)correction.size()) g[i] -= correction[i];
        }
        
        m = cur;
    }
    g.resize(n + 1);
    return g;
}


vector<mint> power_projection(const vector<mint>& f, const vector<mint>& g) {
    using fps = vector<mint>;
    int n = (int)f.size() - 1;
    if (n < 0) return {};
    
    auto pack = [](const vector<fps>& V, int n_x, int width) -> fps {
        int size = n_x * width; 
        if (V.empty()) return {};
        int real_size = (int)V.size() * width + (int)V.back().size();
        fps res(real_size, mint(0));
        for (int i = 0; i < (int)V.size(); ++i) {
            for (int j = 0; j < (int)V[i].size(); ++j) {
                res[i * width + j] = V[i][j];
            }
        }
        return res;
    };

    auto unpack = [](const fps& flat, int n_x, int width, int deg_y_limit) -> vector<fps> {
        vector<fps> res(n_x);
        for (int i = 0; i < n_x; ++i) {
            int start = i * width;
            int end = min((int)flat.size(), start + width);
            if (start >= (int)flat.size()) continue;
            int len = min(end - start, deg_y_limit + 1);
            res[i].resize(len);
            for (int j = 0; j < len; ++j) {
                res[i][j] = flat[start + j];
            }
        }
        return res;
    };

    int k = 1; 
    vector<fps> P(n + 1, fps(1));
    vector<fps> Q(n + 1, fps(2));
    
    for (int i = 0; i <= n; ++i) P[i][0] = (i < (int)g.size() ? g[i] : mint(0));
    
    Q[0][0] = 1;
    for (int i = 1; i <= n; ++i) {
        if (i < (int)f.size()) {
            Q[i] = {mint(0), -f[i]};
        } else {
            Q[i] = {mint(0)};
        }
    }

    int cur_n = n;
    while (cur_n > 0) {
        auto R = Q;
        for (int i = 1; i <= cur_n; i += 2) {
            for (auto& val : R[i]) val = -val;
        }
        int width = 1;
        while(width < 2 * k + 2) width <<= 1;
        
        auto flat_P = pack(P, cur_n + 1, width);
        auto flat_Q = pack(Q, cur_n + 1, width);
        auto flat_R = pack(R, cur_n + 1, width);
        auto flat_S = convolution(flat_P, flat_R);
        auto flat_T = convolution(flat_Q, flat_R);
        int next_n = cur_n / 2;
        int next_k = k * 2;
        int parity = cur_n % 2;
        vector<fps> next_P(next_n + 1);
        for(int i = 0; i <= next_n; ++i) {
            int target_idx = 2 * i + parity;
            int start = target_idx * width;
            if(start >= (int)flat_S.size()) continue;
            int len = min((int)flat_S.size() - start, width); 
            len = min(len, next_k + 1);
            
            next_P[i].resize(len);
            for(int j=0; j<len; ++j) next_P[i][j] = flat_S[start+j];
        }
        vector<fps> next_Q(next_n + 1);
        for(int i = 0; i <= next_n; ++i) {
            int target_idx = 2 * i;
            int start = target_idx * width;
            if(start >= (int)flat_T.size()) continue;
            int len = min((int)flat_T.size() - start, width);
            len = min(len, next_k + 1);
            
            next_Q[i].resize(len);
            for(int j=0; j<len; ++j) next_Q[i][j] = flat_T[start+j];
        }
        
        P = next_P;
        Q = next_Q;
        cur_n /= 2;
        k *= 2;
    }
    auto p_poly = P[0];
    auto q_poly = Q[0];
    p_poly.resize(n + 1, mint(0));
    q_poly.resize(n + 1, mint(0));
    
    auto inv_q = poly_inv(q_poly, n);
    auto res = mul_trunc(p_poly, inv_q, n);
    res.resize(n + 1);
    
    return res;
}

int main() {
    int n,a,b;
    cin >> n >> a >> b;
    ll ans = a;
    for(int i = 0; i < n; i++){
        cout << ans << endl;
        ans = (ans * b);
    }
}
0