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

本文主要是介绍Codeforces 1106F Lunar New Year and a Recursive Sequence (线性代数、线性递推、数论、BSGS、扩展欧几里得算法)...,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

哎呀大水题。。我写了一个多小时。。好没救啊。。

数论板子X合一?

注意: 本文中变量名称区分大小写。

题意: 给一个\(n\)阶递推序列\(f_k=\prod^{n}_{i=1} f_{k-i}^{b_i}\mod P\)其中\(P=998244353\), 输入\(b_1,b_2,...,b_n\)以及已知\(f_1,f_2,...,f_{n-1}=1\), 再给定一个数\(m\)和第\(m\)项的值\(f_m\), 求出一个合法的\(f_n\)值使得按照这个值递推出来的序列满足第\(m\)项的值为给定的\(f_m\).

题解: 首先一个显然的结论是\(f_m\)可以表示成\(\prod^{n}_{i=1} f_i^{a_i}\), 而且由于\(i=1,2,...,n-1\)\(f_i\)的任何次幂都为\(1\), 因此就是\(f_m=f_n^{a}\). 令\(A(m)\)\(f_m\)\(f_n\)的次数,则有\(A[1..n]=[0,0,0,0,...,0,1]\), \(A_m=\sum^{n-1}_{i=1} A(m-i)b_i (m>n)\), 即\(A\)数组满足一个常系数线性递推序列。因此可以用矩阵乘法在\(O(n^3\log m)\)的时间内求出\(A(m)\). 注意因为是指数的运算(\((a^n)^m=a^{nm}\)), 根据费马小定理,这个指数应该模\(\phi(P)=P-1\)而不是\(P\) (\((a^n)^m\mod P=a^{nm\mod (P-1)}\mod P\))

求出来\(a=A(m)\)之后这题就变成了,\(f_m=f_n^a\mod P\), 已知\(f_m, a\), 求出一组合法的\(f_n\).

根据常识,\(998244353\)有原根\(3\), 我们下文令\(G=3\) (实际上任何一个原根均可). 设\(f_m=G^p, f_n=G^q\), 则有\(G^p\equiv (G^q)^a (\mod P)\), \(p\equiv qa(\mod P-1)\), 然后用BSGS求离散对数\(p\), exgcd解出\(q\)就可以了啊……

时间复杂度\(O(\sqrt P\log P+n^3\log P)\)

坑: 注意解同余方程的时候那个\(P\)的系数不要设成负的。

代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<map>
#define llong long long
using namespace std;const int N = 100;
const int G = 3;
const int P = 998244353;
llong quickpow(llong x,llong y)
{llong cur = x,ret = 1ll;for(int i=0; y; i++){if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}cur = cur*cur%P;}return ret;
}
struct Matrix
{llong a[N+3][N+3]; int sz1,sz2,sz;void init() {for(int i=1; i<=sz1; i++) for(int j=1; j<=sz2; j++) a[i][j] = 0ll;}Matrix() {}Matrix(int _sz) {sz = sz1 = sz2 = _sz; init();}Matrix(int _sz1,int _sz2) {sz1 = _sz1,sz2 = _sz2; init();}void uinit(int _sz) {sz = sz1 = sz2 = _sz; for(int i=1; i<=sz; i++) for(int j=1; j<=sz; j++) a[i][j] = (i==j)?1:0;}void output() {for(int i=1; i<=sz1; i++) {for(int j=1; j<=sz2; j++) printf("%lld ",a[i][j]); puts("");}}
};
Matrix operator *(Matrix x,Matrix y)
{Matrix ret = Matrix(x.sz1,y.sz2);for(int i=1; i<=x.sz1; i++){for(int j=1; j<=x.sz2; j++){for(int k=1; k<=y.sz2; k++){ret.a[i][j] = (ret.a[i][j]+x.a[i][k]*y.a[k][j])%(P-1ll);}}}return ret;
}
Matrix mquickpow(Matrix x,llong y)
{Matrix cur = x,ret; ret.uinit(x.sz);for(int i=0; y; i++){if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur;}cur = cur*cur;}return ret;
}
namespace BSGS
{const int B = 31595;map<llong,int> mp;void init(){llong bs = quickpow(G,B); llong j = 1ll;for(int i=0; i<=P; i+=B,j=(j*bs)%P){mp[j] = i;}}llong Logarithm(llong x){llong j = 1ll;for(int i=0; i<=B; i++,j=(j*G)%P){llong tmp = x*j%P;if(mp.count(tmp)){llong ret = (mp[tmp]-i+(P-1))%(P-1);return ret;}}return P-1;}
}
Matrix mA,mB,mC;
llong a[N+3],b[N+3];
int n; llong m,p,q,lq,lx;llong gcd(llong x,llong y) {return y==0 ? x : gcd(y,x%y);}
void exgcd(llong _a,llong _b,llong &_x,llong &_y)
{if(_b==0ll) {_x = 1ll,_y = 0ll; return;}exgcd(_b,_a%_b,_x,_y);llong tmp = _x; _x = _y; _y = tmp-(_a/_b)*_y;
}
llong CongruenceEquation(llong _a,llong _b,llong mod)
{llong g = gcd(_a,mod),x,y;exgcd(_a/g,mod/g,x,y);return (x*(_b/g)%mod+mod)%mod;
}int main()
{BSGS::init();scanf("%d",&n);for(int i=1; i<=n; i++) scanf("%I64d",&b[i]);scanf("%I64d",&m);mA = Matrix(1,n); mA.a[1][1] = 1ll;mB = Matrix(n); for(int i=1; i<n; i++) mB.a[i][i+1] = 1ll; for(int i=1; i<=n; i++) mB.a[i][1] = b[i];mC = mA*mquickpow(mB,m-n); p = mC.a[1][1]; scanf("%I64d",&q);lq = BSGS::Logarithm(q);if(lq%gcd(P-1,p)!=0) {printf("-1\n"); return 0;}lx = CongruenceEquation(p,lq,P-1);llong ans = quickpow(G,lx);printf("%I64d\n",ans);return 0;
}

这篇关于Codeforces 1106F Lunar New Year and a Recursive Sequence (线性代数、线性递推、数论、BSGS、扩展欧几里得算法)...的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/711838

相关文章

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

Java常用注解扩展对比举例详解

《Java常用注解扩展对比举例详解》:本文主要介绍Java常用注解扩展对比的相关资料,提供了丰富的代码示例,并总结了最佳实践建议,帮助开发者更好地理解和应用这些注解,需要的朋友可以参考下... 目录一、@Controller 与 @RestController 对比二、使用 @Data 与 不使用 @Dat

Spring组件初始化扩展点BeanPostProcessor的作用详解

《Spring组件初始化扩展点BeanPostProcessor的作用详解》本文通过实战案例和常见应用场景详细介绍了BeanPostProcessor的使用,并强调了其在Spring扩展中的重要性,感... 目录一、概述二、BeanPostProcessor的作用三、核心方法解析1、postProcessB

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

Python中__new__()方法适应及注意事项详解

《Python中__new__()方法适应及注意事项详解》:本文主要介绍Python中__new__()方法适应及注意事项的相关资料,new()方法是Python中的一个特殊构造方法,用于在创建对... 目录前言基本用法返回值单例模式自定义对象创建注意事项总结前言new() 方法在 python 中是一个

golang字符串匹配算法解读

《golang字符串匹配算法解读》文章介绍了字符串匹配算法的原理,特别是Knuth-Morris-Pratt(KMP)算法,该算法通过构建模式串的前缀表来减少匹配时的不必要的字符比较,从而提高效率,在... 目录简介KMP实现代码总结简介字符串匹配算法主要用于在一个较长的文本串中查找一个较短的字符串(称为

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

numpy求解线性代数相关问题

《numpy求解线性代数相关问题》本文主要介绍了numpy求解线性代数相关问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 在numpy中有numpy.array类型和numpy.mat类型,前者是数组类型,后者是矩阵类型。数组