#原根,BSGS,扩欧,矩阵乘法#CF1106F Lunar New Year and a Recursive Sequence

题目

已知数列 \(f\) 满足 \(f_{1\sim k-1}=1\)\(f_n=m\)

并且知道 \(f_i=(\prod_{j=1}^kf_{i-j}b_j)\bmod{998244353}(i>k)\)

求一组可能的 \(f_k\),不可能存在合法的 \(f_k\) 输出 -1

\(k\leq 100,n\leq 10^9\)


分析

这个连乘很麻烦,如果把它转换成累加那就好了,

取对数肯定不行,因为模数是一个质数,考虑转换成原根的幂。

\(f_i=G^{g_i}\),众所周知该模数的一个原根为 3。

那么就转换成 \(g_{1\sim k-1}=0\)\(g_n\) 可以用 BSGS 求出来。

递推关系就转换成了喜闻乐见的矩阵乘法,可以求出 \(g_n\equiv g_k*x\pmod{998244352}\)

然后直接用扩欧算出一个合法的 \(g_k\) 即可


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
using namespace std;
const int mod=998244353,phi=998244352;
const int MOD=70001,N=111;
int m,A[N][N],B[N],ANS[N],C[N][N];
struct Linked_Hash{
	struct node{int y,w,next;}E[MOD]; int Et,hs[MOD];
	void Clear(){Et=0,memset(hs,-1,sizeof(hs));}
	void Insert(int w,int x){E[++Et]=(node){x,w,hs[w%MOD]},hs[w%MOD]=Et;}
	int locate(int W){
		for (int i=hs[W%MOD];~i;i=E[i].next)
		    if (E[i].w==W) return E[i].y;
		return -1;
	}
}ha;
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void Mo(int &x,int y){x=x+y>=phi?x+y-phi:x+y;}
int BSGS(int a,int b,int mod){
	ha.Clear();
	int ir=sqrt(mod)+1,now=1;
	for (int i=0;i<ir;++i)
	    ha.Insert(1ll*now*b%mod,i),now=1ll*now*a%mod;
	a=now,now=1;
	if (!a) return !b?1:-1;
	for (int i=0;i<=ir;++i){
		int j=ha.locate(now);
		if (j>=0&&i*ir>=j) return i*ir-j;
		now=1ll*now*a%mod;
	}
	return -1;
}
int exgcd(int a,int b,int &x,int &y){
	if (!b) {x=1,y=0; return a;}
	int Gcd=exgcd(b,a%b,y,x);
	y-=a/b*x;
	return Gcd;
}
int ksm(int x,int y){
	int ans=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
	    if (y&1) ans=1ll*ans*x%mod;
	return ans;
}
int main(){
	m=iut(),ANS[0]=1;
	for (int i=0;i<m;++i) A[i][i+1]=1;
	for (int i=0;i<m;++i) A[i][0]=iut()%phi;
	for (int n=iut()-m;n;n>>=1){
		if (n&1){
			for (int i=0;i<m;++i){
				B[i]=0;
				for (int j=0;j<m;++j)
				    Mo(B[i],1ll*ANS[j]*A[j][i]%phi);
			}
			for (int i=0;i<m;++i) ANS[i]=B[i];
		}
		for (int i=0;i<m;++i)
		for (int j=0;j<m;++j){
			C[i][j]=0;
			for (int k=0;k<m;++k)
			    Mo(C[i][j],1ll*A[i][k]*A[k][j]%phi);
		}
		for (int i=0;i<m;++i)
		for (int j=0;j<m;++j)
		    A[i][j]=C[i][j];
	}
	int a=ANS[0],b=phi,x,y,c=BSGS(3,iut(),mod),Gcd=exgcd(a,b,x,y);
	if (c%Gcd) printf("-1");
	else{
		x=(1ll*x*(c/Gcd)%phi+phi)%phi;
		printf("%d",ksm(3,x));
	}
	return 0;
}
posted @ 2022-02-18 18:58  lemondinosaur  阅读(43)  评论(0)    收藏  举报