F. Lunar New Year and a Recursive Sequence(矩阵快速幂+BSGS)

F. Lunar New Year and a Recursive Sequence

题意:

给出 f 1 = f 2 = ⋯ = f k − 1 = 1 f_1=f_2=\cdots=f_{k-1}=1 f1=f2==fk1=1 b 1 , b 2 ⋯ b k b_1,b_2\cdots b_k b1,b2bk,还有递推方程
f i = f i − 1 b 1 f i − 2 b 2 ⋯ f i − k b k f_i=f_{i-1}^{b_1}f_{i-2}^{b_2}\cdots f_{i-k}^{b_k}\\ fi=fi1b1fi2b2fikbk

问是否存在一个 f k f_k fk使得 f n ≡ m ( m o d   p ) f_n\equiv m(mod~p) fnm(mod p)成立;

思路:

矩阵快速幂 + B S G S +BSGS +BSGS

因为 n n n很大,所以不能直接推出 f n f_n fn f k f_k fk的多少次方,观察递推式全是乘法,我们就想到用矩阵加速。

先推出矩阵。

假设 k = 4 k=4 k=4,则可以推出下面的式子。
f k = f k f k + 1 = f k b 1 f k − 1 b 2 f k − 2 b 3 f k − 3 b 4 = f k b 1 f k + 2 = f k + 1 b 1 f k b 2 f k − 1 b 3 f k − 2 b 4 = ( f k b 1 ) b 1 f k b 2 = f k b 1 2 + b 2 f k + 3 = f k + 2 b 1 f k + 1 b 2 f k b 3 f k − 1 b 4 = f k b 1 3 + 2 b 1 ∗ b 2 + b 3 f k + 4 = f k + 3 b 1 f k + 2 b 2 f k + 1 b 3 f k b 4 = f k b 1 4 + 3 b 1 2 b 2 + 2 b 1 b 3 + b 2 2 + b 4 f k + 5 = f k + 4 b 1 f k + 3 b 2 f k + 2 b 3 f k + 1 b 1 \begin{aligned} &f_k=f_k\\ &f_{k+1}=f_k^{b_1}f_{k-1}^{b_2}f_{k-2}^{b_3}f_{k-3}^{b_4}=f_k^{b_1}\\ &f_{k+2}=f_{k+1}^{b_1}f_k^{b_2}f_{k-1}^{b_3}f_{k-2}^{b_4}=(f_k^{b_1})^{b_1}f_k^{b_2}=f_k^{b_1^2+b_2}\\ &f_{k+3}=f_{k+2}^{b_1}f_{k+1}^{b_2}f_k^{b_3}f_{k-1}^{b_4}=f_k^{b_1^3+2b_1*b_2+b_3}\\ &f_{k+4}=f_{k+3}^{b_1}f_{k+2}^{b_2}f_{k+1}^{b_3}f_k^{b_4}=f_k^{b_1^4+3b_1^2b_2+2b_1b_3+b_2^2+b_4}\\ &f_{k+5}=f_{k+4}^{b_1}f_{k+3}^{b_2}f_{k+2}^{b_3}f_{k+1}^{b_1}\\ \end{aligned} fk=fkfk+1=fkb1fk1b2fk2b3fk3b4=fkb1fk+2=fk+1b1fkb2fk1b3fk2b4=(fkb1)b1fkb2=fkb12+b2fk+3=fk+2b1fk+1b2fkb3fk1b4=fkb13+2b1b2+b3fk+4=fk+3b1fk+2b2fk+1b3fkb4=fkb14+3b12b2+2b1b3+b22+b4fk+5=fk+4b1fk+3b2fk+2b3fk+1b1

我们可以看出每个 f i f_i fi都是由前 k k k f f f值推出来的,所以我们设 f i f_i fi的对应的 f k f_k fk的系数是 g i g_i gi

我们就能找到一个一维的矩阵乘法
[ g 4 , g 3 , g 2 , g 1 ] × [ b 1 b 2 b 3 b 4 ] = g 5 \left[ \begin{matrix} g_4,g_3,g_2,g_1 \end{matrix} \right]\times \left[ \begin{matrix} b_1\\b_2\\b_3\\b_4 \end{matrix} \right]=g_5 [g4,g3,g2,g1]×b1b2b3b4=g5

[ g 5 , g 4 , g 3 , g 2 ] × [ b 1 b 2 b 3 b 4 ] = g 6 \left[ \begin{matrix} g_5,g_4,g_3,g_2 \end{matrix} \right]\times \left[ \begin{matrix} b_1\\b_2\\b_3\\b_4 \end{matrix} \right]=g_6 [g5,g4,g3,g2]×b1b2b3b4=g6

所以我们把矩阵扩展到 k k k维,希望得到一个包含 g i g_i gi的矩阵乘以另一个矩阵得到包含形式相同且包含 g i + 1 g_{i+1} gi+1的矩阵,

推出:

[ g 7 g 6 g 5 g 4 g 6 g 5 g 4 g 3 g 5 g 4 g 3 g 2 g 4 g 3 g 3 g 1 ] × [ b 1 1 0 0 b 2 0 1 0 b 3 0 0 1 b 4 0 0 0 ] = [ g 8 g 7 g 6 g 5 g 7 g 6 g 5 g 4 g 6 g 5 g 4 g 3 g 5 g 4 g 3 g 2 ] \left[ \begin{matrix} g_7&g_6&g_5&g_4 \\g_6&g_5&g_4&g_3 \\g_5&g_4&g_3&g_2 \\g_4&g_3&g_3&g_1 \end{matrix} \right]\times \left[ \begin{matrix} b_1&1&0&0 \\b_2&0&1&0 \\b_3&0&0&1 \\b_4&0&0&0 \end{matrix} \right]=\left[\begin{matrix} g_8&g_7&g_6&g_5 \\g_7&g_6&g_5&g_4 \\g_6&g_5&g_4&g_3 \\g_5&g_4&g_3&g_2 \end{matrix} \right] g7g6g5g4g6g5g4g3g5g4g3g3g4g3g2g1×b1b2b3b4100001000010=g8g7g6g5g7g6g5g4g6g5g4g3g5g4g3g2

通过 k = 4 k=4 k=4的特例,我们能够推出 k k k是范围内的任意矩阵。

我们就能推出 f n f_n fn f k f_k fk的多少次方,设 f n f_n fn = f k a =f_k^a =fka

现在的问题是已知 a a a,求是否存在 f k f_k fk使 f k a ≡ m ( m o d   p ) f_k^a\equiv m(mod~p) fkam(mod p)成立。

这个就是之前的 b s g s bsgs bsgs的进阶篇:进阶篇

C o d e : Code: Code:

#include
using namespace std;
typedef long long ll;
const int N = 1e2+10;
const int mod = 998244353;
vector<ll> a;
ll b[N], k;
struct matrix {
     //矩阵
    ll s[N][N];
    matrix operator * (const matrix &t) {
     //矩阵乘法
        matrix tmp;
        for(int i=1; i<=k; i++) {
     
            for(int j=1; j<=k; j++) {
     
                tmp.s[i][j] = 0;
                for(int l=1; l<=k; l++) {
     
                    tmp.s[i][j] = (tmp.s[i][j] + s[i][l] * t.s[l][j] % (mod-1)) % (mod-1);
                }
            }
        }
        return tmp;
    }
} A, I, B;

matrix mqpow(matrix t, ll y) {
     //矩阵快速幂
    matrix ans = I;
    while(y) {
     
        if(y & 1) ans = ans * t;
        t = t * t;
        y >>= 1;
    }
    return ans;
}

ll qpow(ll x, ll y) {
     //快速幂
    ll ans = 1;
    while(y) {
     
        if(y & 1) ans = ans * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return  ans;
}

ll G(ll p) {
     //求原根,就是3,可以直接存下来,就不用再计算了。
    vector<int> v;
    ll phi = p-1, tmp = phi;
    for(int i=2; 1ll*i*i<=tmp; i++) {
     
        if(tmp % i == 0) {
     
            v.push_back(i);
            while(tmp % i == 0) tmp /= i;
        }
    }
    if(tmp > 1) v.push_back(tmp);
    for(int i=2; i<=phi; i++) {
     
        int f = 1;
        for(auto it : v) {
     
            if(i % it == 0) {
     
                f = 0;
                break;
            }
            if(f) return i;
        }
    }
    return -1;
}
unordered_map<ll, ll> mp;
ll bsgs(ll aaa, ll b, ll p) {
     //经典bsgs
    mp.clear();
    if(aaa % p == 0 && b % p != 0) return -1;
    int k = ceil(sqrt(p));
    for(int i=0; i<=k; i++) {
     
        mp[b] = i, b = b * aaa % mod;
    }
    ll aa = qpow(aaa, k), A = aa;
    // cout << aa<< endl;
    for(int i=1; i<=k; i++) {
     
        if(mp[A]) return 1ll*i*k - mp[A];
        A = A * aa % mod;
    }
    return -1;
}
int main() {
         
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
	//预处理+输入
    scanf("%lld", &k);
    for(int i=1; i<=k; i++) I.s[i][i] = 1;
    for(int i=1; i<=k; i++) {
     
        scanf("%lld", &b[i]);
    }
    for(int i=1; i<k; i++) a.push_back(0);
    a.push_back(1); 
  	//构建矩阵
    for(int i=1; i<=k; i++) {
     
        ll tmp = 0;
        for(int j=1; j<=k; j++) {
     
            tmp = (tmp + b[j] * a[a.size()-j] % (mod-1)) % (mod-1);
        }
        a.push_back(tmp);
    }
    ll n, m, aa;
    scanf("%lld%lld", &n, &m);
    //判断是否已经算出指数大小。
    if(n <= 2*k) {
     
        aa = a[n-1] % (mod-1);
    }
    else {
     
    	//构造矩阵。
        for(int j=1, i=a.size()-1; j<=k; j++, i--) {
     
            int l = 1;
            while(l <= k) {
     
                A.s[j][l] = a[i-l+1];
                // cout << i-l+1 << endl;
                l++;
            }
        }
        for(int i=1; i<=k; i++) {
     
            for(int j=1; j<=k; j++) {
     
                if(i == 1) B.s[j][i] = b[j];
                else if(j == i-1) {
     
                    B.s[j][i] = 1;
                }
            }
        }
        A = A * mqpow(B, n-2*k);
        aa = A.s[1][1]%(mod-1);
    }
    //求原根+bsgs。
    ll g = G(mod);
    ll ans = bsgs(qpow(g, aa), m, mod);
    if(ans != -1) cout << qpow(g, ans);
    else cout << -1 << endl;
    return 0;
}

你可能感兴趣的:(题解,codeforces)