CF1106F Lunar New Year and a Recursive Sequence 线性递推 + k次剩余

已知\(f_i = \prod \limits_{j = 1}^k f_{i - j}^{b_j}\;mod\;998244353\),并且\(f_1, f_2, ..., f_{k - 1} = 1\)\(f_k = a\),已知\(f_n = m\),试求\(a\)

易知\(f_n = f_k^p\)

对于\(p\)满足递推式\(g[i] = \sum \limits_{j = 1}^k b[j] * g[i - j]\)

这是常系数线性递推,由于\(k \leq 100\),因此矩阵快速幂即可

那么问题就变为了\(f_k^p = m(\;mod\;998244353)\),求\(f_k\)

由于\(998244353\)的原根为\(3\),因此把\(m\)离散之后,可以写出方程

\(f_k = 3^s(mod\;998244353)\)\(m = 3^t\),那么有\(3^{sp} = 3^t (mod\;998244353)\)

由欧拉定理\(sp = t(mod\;998244352)\),然后解一下这个同余方程

有解则输出,无解就无解

复杂度\(O(k^3 \log n + \sqrt{998244353})\)


#include <map>
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define de double
#define ll long long
#define ri register int
#define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
#define drep(io, ed, st) for(ri io = ed; io >= st; io --)

#define gc getchar
inline int read() {
    int p = 0, w = 1; char c = gc();
    while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
    while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
    return p * w;
}
    
const int sid = 105;
const int mod = 998244353;
const int g = 3;

inline int mul(int a, int b) { return 1ll * a * b % mod; }
inline int fp(int a, int k) {
    int ret = 1;
    for( ; k; k >>= 1, a = mul(a, a))
        if(k & 1) ret = mul(ret, a);
    return ret;
}

int n, m, k, b[sid];
struct mtx {
    int f[sid][sid];
    mtx() {}
    mtx(int flag) {
        if(flag == 0) {
            for(int i = 0; i < k; i ++)
            for(int j = 0; j < k; j ++)
            f[i][j] = 0;
        } 
        if(flag == 1) {
            for(int i = 0; i < k; i ++)
            for(int j = 0; j < k; j ++)
            f[i][j] = (i == j) ? 1 : 0;
        }
    }
    int* operator [] (const int x) {
        return f[x];
    }
    friend mtx operator * (mtx a, mtx b) {
       mtx c(0);
        for(int i = 0; i < k; i ++)
        for(int j = 0; j < k; j ++)
        for(int p = 0; p < k; p ++)
        c[i][j] = (c[i][j] + 1ll * a[i][p] * b[p][j] % (mod - 1)) % (mod - 1);
        return c;
    }
} A, B;
    
inline mtx fp(mtx a, int k) {
    mtx ret(1);
    for( ; k; k >>= 1, a = a * a)
        if(k & 1) ret = ret * a;
    return ret;
}
    
map <int, int> H;
inline int BSGS(int A, int B) {
    H.clear(); H[1] = 0;
    int Ai = 1, Aj = 1, m = ceil(sqrt(mod));
    for(ri i = 1; i < m; i ++) Ai = 1ll * Ai * A % mod, H[1ll * Ai * B % mod] = i;
    Ai = 1ll * Ai * A % mod;
    for(ri i = 1; i <= m; i ++) {
        Aj = 1ll * Aj * Ai % mod;
        if(H[Aj]) return 1ll * i * m - H[Aj];
    }
}

inline int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}

inline void exgcd(int &x, int &y, int a, int b) {
    if(!b) { x = 1; y = 0; return; }
    exgcd(y, x, b, a % b); y -= a / b * x;
}
    
inline void Solve() {
    A[0][k - 1] = 1;
    rep (i, 0, k - 1) B[i][k - 1] = b[k - i];
    rep (i, 0, k - 2) B[i + 1][i] = 1;
    
    A = A * fp(B, n - k);

    int p = A[0][k - 1], t = BSGS(g, m);
    if(t % gcd(p, mod - 1)) printf("-1\n");
    else {
        int gd = gcd(p, mod - 1);
        int x, y, a = p, b = mod - 1;
        t /= gd; a /= gd; b /= gd;
        exgcd(x, y, a, b); 
        x = (x + mod - 1) % (mod - 1);
        x = 1ll * x * t % (mod - 1);
        printf("%d\n", fp(g, x));
    }
}
    
int main() {
    k = read();
    rep(i, 1, k) b[i] = read();
    n = read(); m = read();
    Solve();
    return 0;
}
posted @ 2019-02-01 08:01 remoon 阅读(...) 评论(...) 编辑 收藏