CF1106F Lunar New Year and a Recursive Sequence 原根、矩陣快速冪、高次剩余、BSGS
傳送門
好久沒寫數論題了寫一次調了1h
首先發現遞推式是一個乘方的形式,線性遞推和矩陣快速冪似乎都做不了,那麽是否能夠把乘方運算變成加法運算和乘法運算呢?
使用原根!學過\(NTT\)的都知道\(998244353\)的原根\(G=3\)。
使用原根之後,可以得到一個等價的新遞推式:\(G^{g_i} = \prod\limits _ {j=1}^k G^{g_{i - j} \times b_j} \mod 998244353(G^{g_i} \equiv f_i\mod 998244353)\),它等價於\(g_i = \sum\limits_{j=1}^k g_{i-j} \times b_j \mod 998244352\)
可現在知道的是\(f_n\)的值,不知道\(f_k\)的值。
考慮:令\(G_k=1\),得到\(G_n\)的值\(x\),那麽可以知道\(f_k^x \equiv f_n \mod 998244353\)。
這是一個模意義下的高次剩余方程,要怎麽求解呢?
同樣使用原根。設\(f_{k} = G^b \mod 998244353\),通過\(BSGS\)求出\(f_n = G^y \mod 998244353\),那麽原式變成\(G^{bx} \equiv G^y \mod 998244353\),即\(bx \equiv y \mod 998244352\)
一些打比賽時被坑到的點:
①\(998244352 = 2^{23} \times 7 \times 17\),求逆元要用歐拉定理或者拓展歐幾裏得
②\(998244351 \times 998244351 \times 100 > 2^{63}\),這意味著矩陣相乘不能算完再一起取模
#include<bits/stdc++.h> #define int long long //This code is written by Itst using namespace std; inline int read(){ int a = 0; char c = getchar(); bool f = 0; while(!isdigit(c)){ if(c == ‘-‘) f = 1; c = getchar(); } while(isdigit(c)){ a = (a << 3) + (a << 1) + (c ^ ‘0‘); c = getchar(); } return f ? -a : a; } const int MOD = 998244353 , G = 3; int K; struct matrix{ int a[100][100]; int* operator [](int x){return a[x];} matrix(){memset(a , 0 , sizeof(a));} matrix operator *(matrix b){ matrix c; for(int i = 0 ; i < K ; ++i) for(int j = 0 ; j < K ; ++j) for(int k = 0 ; k < K ; ++k) c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % (MOD - 1); return c; } }S , T; inline int gcd(int a , int b){ int r = a % b; while(r){ a = b; b = r; r = a % b; } return b; } inline int poww(int a , int b , int mod = MOD){ int times = 1; while(b){ if(b & 1) times = times * a % mod; a = a * a % mod; b >>= 1; } return times; } map < int , int > Hash; inline int BSGS(int x){ int t = sqrt(MOD) + 1 , times = x; for(int i = 0 ; i < t ; i++){ Hash[times] = i; times = times * G % MOD; } times = poww(G , t); int now = times; for(int i = 1 ; i <= t + 1 ; i++){ if(Hash.count(now)){ return i * t - Hash[now]; } now = now * times % MOD; } return -1; } int phi(int x){ int times = x; for(int i = 2 ; i * i <= x ; ++i){ if(x % i == 0){ times = times / i * (i - 1); while(x % i == 0) x /= i; } } if(x - 1) times = times / x * (x - 1); return times; } signed main(){ #ifndef ONLINE_JUDGE //freopen("in" , "r" , stdin); //freopen("out" , "w" , stdout); #endif K = read(); for(int i = 0 ; i < K ; ++i) T[K - i - 1][K - 1] = read() % (MOD - 1); int N = read() - K; int t = BSGS(read()); for(int i = 0 ; i + 1 < K ; ++i) T[i + 1][i] = 1; S[0][K - 1] = 1; while(N){ if(N & 1) S = S * T; T = T * T; N >>= 1; } int cur = S[0][K - 1] , p = gcd(cur , MOD - 1); if(t % p != 0) puts("-1"); else{ t /= p; cur /= p; int mod = (MOD - 1) / p; cout << poww(G , poww(cur , phi(mod) - 1 , mod) * t % mod); } return 0; }
CF1106F Lunar New Year and a Recursive Sequence 原根、矩陣快速冪、高次剩余、BSGS