@description@

定义递推数列 f:

(1)f[1] = f[2] = ... f[k-1] = 1,f[k] 是一个未知量。

(2)f[i] = (f[i-1]^b[1]) * (f[i-2]^b[2]) * ... *(f[i-k]^b[k]) mod 998244353。

其中 k 和 b[1...k] 是给定的常量。现在已知数列的第 n 项 f[n] = m,求 f[k]。

input

第一行一个整数 k (1 <= k <= 100)。

接下来一行 k 个整数 b1, b2, ..., bk (1 <= bi < 998244353)。

接下来一行两个整数 n, m (k < n <= 10^9, 1 <= m < 998244353)。

output

输出 fk 的值。若不存在,输出 -1。若多解,输出任意一个。

sample input

3

2 3 5

4 16

sample output

4

@solution@

首先,我们想要在 fk 与 fn 之间建立关系。

不难猜想到 fn = fk^x,同时这也暗示我们可以将 1 看成 fk^0。

这样的话原本是非线性递推式,就可以变成指数的线性递推式。可以用矩阵快速幂解出 x 的值。

现在,我们已知 fk^x = fn = m mod 998244353,想要解出 fk 的值。

这是一个经典的数论问题:高次剩余。它有一些复杂的方法,但是对于这个特殊的模数,我们还有一种较为简洁的方法:利用原根。

根据原根的性质,我们可以将任意一个数写成原根的幂的形式。这样上面的式子就会变为 g^(px) = g^q mod 998244353。

通过 BSGS 可以快速解出 q 的值。这样我们只需要根据指数相等列出同余方程用 exgcd 解出 p 的值就可以解决此题了。

@accepted code@

#include<cstdio>
#include<vector>
#include<cmath>
using namespace std;
const int MAXK = 100 + 5;
const int MOD = 998244353;
const int MODPW = MOD - 1;
const int HASHSIZE = 1000037;
struct node{
int ind, key;
node(int _i=0, int _k=0):ind(_i), key(_k){}
};
vector<node>h[HASHSIZE];
void hash_insert(int n, int x) {
h[x%HASHSIZE].push_back(node(n, x));
}
int hash_search(int x) {
int y = x%HASHSIZE;
for(int i=0;i<h[y].size();i++)
if( h[y][i].key == x ) return h[y][i].ind;;
return -1;
}
void hash_clear() {
for(int i=0;i<HASHSIZE;i++)
h[i].clear();
}
struct matrix{
int m[MAXK][MAXK];
int r, c;
}A, B;
matrix operator * (matrix A, matrix B) {
matrix C; C.r = A.r, C.c = B.c;
for(int i=0;i<C.r;i++)
for(int j=0;j<C.c;j++) {
C.m[i][j] = 0;
for(int k=0;k<A.c;k++)
C.m[i][j] = (C.m[i][j] + 1LL*A.m[i][k]*B.m[k][j]%MODPW)%MODPW;
}
return C;
}
matrix mpow(matrix A, int p) {
matrix ret; ret.r = ret.c = A.r;
for(int i=0;i<ret.r;i++)
for(int j=0;j<ret.c;j++)
ret.m[i][j] = (i == j);
while( p ) {
if( p & 1 ) ret = ret*A;
A = A*A;
p >>= 1;
}
return ret;
}
int solve1() {
int k, n; scanf("%d", &k);
for(int i=0;i<k;i++) scanf("%d", &A.m[k-1][k-i-1]);
A.r = A.c = B.r = k; B.c = 1;
for(int i=0;i<k;i++) B.m[i][0] = 0;
B.m[k-1][0] = 1;
for(int i=0;i<k-1;i++)
for(int j=0;j<k;j++)
A.m[i][j] = 0;
for(int i=0;i<k-1;i++) A.m[i][i+1] = 1;
scanf("%d", &n); B = mpow(A, n-k)*B;
return B.m[k-1][0];
}
int pow_mod(int b, int p, int mod) {
int ret = 1;
while( p ) {
if( p & 1 ) ret = 1LL*ret*b%mod;
b = 1LL*b*b%mod;
p >>= 1;
}
return ret;
}
int BSGS(int a, int b) {
hash_clear();
int m = int(ceil(sqrt(MOD))), tmp = 1, tmp2;
for(int i=0;i<=m;i++) {
if( i == m ) tmp2 = tmp;
hash_insert(i, 1LL*tmp*b%MOD);
tmp = 1LL*tmp*a%MOD;
}
tmp = tmp2;
for(int i=1;i<=m;i++) {
if( hash_search(tmp) != -1 ) {
return i*m - hash_search(tmp);
}
tmp = 1LL*tmp*tmp2%MOD;
}
}
typedef long long ll;
ll exgcd(ll a, ll b, ll &x, ll &y) {
if( b == 0 ) {
x = 1, y = 0;
return a;
}
else {
ll x1, y1;
ll d = exgcd(b, a%b, x1, y1);
x = y1;
y = x1 - a/b*y1;
return d;
}
}
int solve2(int a, int p) {
int b = BSGS(3, a);
ll x, y, d = exgcd(p, MODPW, x, y);
if( b % d ) return -1;
else {
x = (1LL*x*b/d%MODPW + MODPW)%MODPW;
return pow_mod(3, x, MOD);
}
}
int main() {
int m, p = solve1(); scanf("%d", &m);
printf("%d\n", solve2(m, p));
}

@details@

WC2019 讲了“简单”数论,所以就记住了这一算法,然后没想到这一次就用到了。

然而我并没有写过 BSGS,比赛的时候现学的(又是这样嘛……上一次 manacher 也是比赛的时候现学的……)

所以打 CF 还是有用的 2333。

靠着 CF 官方评测系统出锅,续了 40 min,终于把这道题写出来了。

人生第一次 AK。感谢 CF 的评测系统。

只不过 unrated 有点儿可惜 www。

本次比赛好像就这道题有点儿意思(因为是没有写过的新知识)。

A:大模拟

B:英语阅读理解 + 大模拟

C:常见贪心结论

D:一个关于图论的简单贪心

E:英语阅读理解 + 简单 dp

@codeforces - 1106F@ Lunar New Year and a Recursive Sequence的更多相关文章

  1. Codeforces 1106F Lunar New Year and a Recursive Sequence | BSGS/exgcd/矩阵乘法

    我诈尸啦! 高三退役选手好不容易抛弃天利和金考卷打场CF,结果打得和shi一样--还因为queue太长而unrated了!一个学期不敲代码实在是忘干净了-- 没分该没分,考题还是要订正的 =v= 欢迎 ...

  2. Codeforces 1106F Lunar New Year and a Recursive Sequence (数学、线性代数、线性递推、数论、BSGS、扩展欧几里得算法)

    哎呀大水题..我写了一个多小时..好没救啊.. 数论板子X合一? 注意: 本文中变量名称区分大小写. 题意: 给一个\(n\)阶递推序列\(f_k=\prod^{n}_{i=1} f_{k-i}b_i ...

  3. CF1106F Lunar New Year and a Recursive Sequence

    题目链接:CF1106F Lunar New Year and a Recursive Sequence 大意:已知\(f_1,f_2,\cdots,f_{k-1}\)和\(b_1,b_2,\cdot ...

  4. CF1106F Lunar New Year and a Recursive Sequence 原根、矩阵快速幂、BSGS

    传送门 好久没写数论题了写一次调了1h 首先发现递推式是一个乘方的形式,线性递推和矩阵快速幂似乎都做不了,那么是否能够把乘方运算变成加法运算和乘法运算呢? 使用原根!学过\(NTT\)的都知道\(99 ...

  5. 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 ...

  6. CF1106F Lunar New Year and a Recursive Sequence(矩阵快速幂+bsgs+exgcd)

    题面 传送门 前置芝士 \(BSGS\) 什么?你不会\(BSGS\)?百度啊 原根 对于素数\(p\)和自然数\(a\),如果满足\(a^x\equiv 1\pmod{p}\)的最小的\(x\)为\ ...

  7. CF1106F Lunar New Year and a Recursive Sequence——矩阵快速幂&&bsgs

    题意 设 $$f_i = \left\{\begin{matrix}1 , \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \  i < k\\ ...

  8. hdu 5950 Recursive sequence 矩阵快速幂

    Recursive sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  9. HDU 5950 Recursive sequence 【递推+矩阵快速幂】 (2016ACM/ICPC亚洲区沈阳站)

    Recursive sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

随机推荐

  1. Sessions 与Cookies详解

     一.Cookie 是什么? HTTP协议是无状态的,每一次数据交换完毕就结束,服务器端和客户端的链接就会关闭,每次交换数据都需要建立新的链接.例如:我逛淘宝买东西,我看上了易宝棒棒糖,而我下单的时候 ...

  2. Python之路,Day5 - 常用模块学习 (转载Alex)

    本节大纲: 模块介绍 time &datetime模块 random os sys shutil json & picle shelve xml处理 yaml处理 configpars ...

  3. 【模板】Vector存图 + SPFA

    最近愉快地决定要由边集数组转向Vector存图,顺便开始图论集训 老惯例,以题写模板 P1339 [USACO09OCT]热浪Heat Wave 题目描述 The good folks in Texa ...

  4. 定位真机运行能用但是打包成apk就不能用的解决方法

    打包apk的SHA1,与key的SHA1(这是多人开发的通病不同电脑共同开发一个app的常见错误之一)不一致.解决方法: 今天虽然离职了,但是今天遇到的是,当我在用高德地图开发的时候,在Android ...

  5. OpenLayers使用弹出窗口

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...

  6. 【JZOJ3215】【SDOI2013】费用流

    ╰( ̄▽ ̄)╭ 对于一张给定的 运输网络 ,Alice 先确定一个最大流 ,如果有多种解, Alice 可以任选一种: 之后 Bob在每条边上分配单位花费 (单位花费必须是非负实数), 要求所有边的单 ...

  7. vue+axios 对restful 请求封装

    礼拜天来公司整理项目,项目是最近开始重构的,里面的各种http请求接口是restful结构的(为了提升项目的比格),整理一下笔记 [restful介绍][1]博主讲的很详细 技术栈: vue + vu ...

  8. 关于PHP学习--摘自知乎

    主要是学框架(其实也没啥可学的).数据库.服务器.linux. 所以我推荐apache/nginx文档,框架的文档,mysql的文档,linux使用说明,等等等等. PHP: PHP 手册MySQL ...

  9. 启动Jmeter录制代理进行录制,报 jmeter.protocol.http.proxy.ProxyControl

    使用jmeter代理录制Http请求时,启动HTTP(S) Test Script Recorder报jmeter.protocol.http.proxy.ProxyControl, 日志为: 201 ...

  10. 基于OPNET的路由协议仿真教程(AODV、OLSR 、DSR等)

    前言: 目前由于项目需要,学习了基于opnet的网络仿真方法,发现该软件的学习资料少之又少,所以将自己搜集到的学习资料进行整理,希望能帮助后来的人. 主要参考资料:OPNET网络仿真(清华陈敏版) 仿 ...