Codeforces 1106F(数论)
Posted alphawa
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 1106F(数论)相关的知识,希望对你有一定的参考价值。
要点
- 998244353的原根g = 3,意味着对于任意[1 <= x,y<p][x eq y][g^x\%p eq g^y\%p]因此可以有构造序列(q(a)与a一一对应,g^{q(a)}\%p=a)。那么对应到这道题上,因为(f_i)是%p的,所以构造(h_i)序列,使得[g^{h_i}\%p=f_i=prod_{j=1}^{k}(f_{i-j})^{b_j}\%p=g^{sum_{j=1}^k{h_{i-j} imes b_j}}\%p][ecause 原根的唯一对应性质且g^{p-1}\%p=1][ herefore h_iequiv sum_{j=1}^kh_{i-j} imes b_j(mod p-1)]
- 以上就是本题全部关键了,接下来就是数论复习内容了。
- 首先看到这个熟悉的式子想到我们可以(\%(p-1))意义下矩阵快速幂求解,往常是给前面的项求第n项,这次是有(h_n)求(h_k)。
- 其中(h_n)的求法是BSGS算法
- 矩阵快速幂以后,因为题面说初始除了(f_k)以外都是1,所以(h_{1…k-1})都是0,故而有[h_nequiv Matrix[0][0] imes h_k(mod p-1)]
- 这就变成了(ah_xequiv c(\%b)),变形为(ax+by=c)即可用扩展欧几里得求解,若有解,用快速幂求得(f_k),否则输出-1.
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int p = 998244353, g = 3;
int K, b[101], n, fn, hn, hk;
struct Matrix {
int n;
int v[101][101];
Matrix(int n) { memset(v, 0, sizeof v); this->n = n; }
friend Matrix operator * (Matrix A, Matrix B) {
int n = A.n;
Matrix ret(n);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
for (int k = 0; k < n; k++) {
ret.v[i][j] = ((ll)ret.v[i][j] + (ll)A.v[i][k] * B.v[k][j] % (p - 1)) % (p - 1);
}
return ret;
}
friend Matrix operator ^ (Matrix A, int k) {
int n = A.n;
Matrix ret(n);
for (int i = 0; i < n; i++)
ret.v[i][i] = 1;
for (; k; k >>= 1) {
if (k & 1) ret = ret * A;
A = A * A;
}
return ret;
}
};
namespace BSGS {
const int maxm = 1e5 + 1000;
int hash_table[maxm], val[maxm];
int ksm(int a, int b, int mod) {
int res = 1;
for (; b; b >>= 1) {
if (b & 1) res = (ll)res * a % mod;
a = (ll)a * a % mod;
}
return res;
}
int find(int n) {
int id = n % maxm;
while (hash_table[id] >= 0 && hash_table[id] != n)
id = (id + 1) % maxm;
return id;
}
int bsgs(int a, int b, int p) {
a %= p, b %= p;
if (!a) return b ? -1 : 1;
memset(hash_table, -1, sizeof hash_table);
int m = sqrt(p) + 1;
int now = b;
hash_table[now % maxm] = now;
val[now % maxm] = 0;
for (int i = 1; i <= m; i++) {
now = (ll)now * a % p;
int pos = find(now);
hash_table[pos] = now;
val[pos] = i;
}
int t = ksm(a, m, p);
now = 1;
for (int i = 1; i <= m; i++) {
now = (ll)now * t % p;
int pos = find(now);
if (hash_table[pos] >= 0) {
return i * m - val[pos];
}
}
return -1;
}
}
namespace EXGCD {
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
ll exgcd(ll a, ll b, ll &x, ll &y) {
if (!b) {
x = 1, y = 0;
return a;
}
ll q = exgcd(b, a % b, y, x);
y -= a / b * x;
return q;
}
int solve(int a, int b, int c) {//ax = c (% b)求x的解
if (!c) return 0;
int q = gcd(a, b);
if (c % q) return -1;
a /= q, b /= q, c /= q;
ll ans, __;
exgcd((ll)a, (ll)b, ans, __);
ans = (ans * c % b + b) % b;
return ans;
}
}
int main() {
scanf("%d", &K);
for (int i = 0; i < K; i++)
scanf("%d", &b[i]), b[i] %= p - 1;
scanf("%d%d", &n, &fn);
hn = BSGS::bsgs(g, fn, p);
Matrix A(K);
for (int i = 0; i < K; i++)
A.v[0][i] = b[i];
for (int j = 1; j < K; j++)
A.v[j][j - 1] = 1;
A = A ^ (n - K);
hk = EXGCD::solve(A.v[0][0], p - 1, hn);
if (hk >= 0) {
printf("%d
", BSGS::ksm(g, hk, p));
} else {
printf("-1
");
}
return 0;
}
以上是关于Codeforces 1106F(数论)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces1106F BSGS矩阵快速幂exgcd
Codeforces 1016G Appropriate Team 数论 FWT
CodeForces 743C Vladik and fractions (数论)
CodeForces 1047C Enlarge GCD(数论)题解