CF 1106 F. Lunar New Year and a Recursive Sequence

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/86739330

给出一个k阶递推式 ( m o d 998244353 ) \pmod{998244353} f [ 1... k 1 ] = 1 , f [ n ] = m f[1...k-1] = 1,f[n] =m
f [ k ] f[k]
这个递推式显然让人想两边同时求一个对数。
g [ i ] = log f [ i ] g[i] = \log f[i]
g [ i ] = j = 1 k b [ j ] g [ i j ] g[i] = \sum_{j=1}^k b[j]g[i-j]
常系数线性递推???
然后发现 g [ 1... k 1 ] = 0 g[1...k-1] = 0
g [ n ] g[n] 又是 g [ 1... k ] g[1...k] 的线性组合。
那么设 g [ n ] = i = 1 k c [ i ] g [ i ] g[n] = \sum_{i=1}^kc[i] * g[i]
可以发现 g [ n ] = c [ k ] g [ k ] g[n] = c[k] * g[k]
c[k]可以通过特征多项式+多项式取模来计算矩阵快速幂来计算。
g[n]可以通过。。。好吧这里 log \log 的底数可以任意所以模意义下的 log \log 我们可以用998244353的原根3做底数,然后模意义下的 log \log 就可以用bsgs来 O ( n ) O(\sqrt n) 计算了。
然后就是同余方程:
c [ k ] g [ k ] = g [ n ] ( m o d 998244353 ) c[k] * g[k] = g[n] \pmod {998244353}
这个gcd一下就可以判断有无解。
exgcd一下就可以计算出一组解。
这个题好像就这么精彩的结束了?(好像可以把k开到 1 0 5 10^5 的样子)
AC Code:

#include<cstdio>
#include<algorithm>
#include<map>
#include<cstring>
#define maxn 105
#define mod 998244352
#define Mod 998244353
#define S 100005
using namespace std;

map<int,int>mp;
int k,n,m;

struct mat
{
	int a[maxn][maxn];
	mat(){memset(a,0,sizeof a);}
	mat operator *(const mat &B)const
	{
		mat ret;
		for(int i=0;i<k;i++)
			for(int j=0;j<k;j++) if(a[i][j])
				for(int p=0;p<k;p++) if(B.a[j][p])
					ret.a[i][p] = (ret.a[i][p] + 1ll * a[i][j] * B.a[j][p]) % mod;
		return ret;
	}
}b;

mat Pow(mat base,int p)
{
	mat ret;
	for(int i=0;i<k;i++)
		ret.a[i][i] = 1;
	for(;p;p>>=1,base=base*base) 
		if(p&1) 
			ret = ret * base;
	return ret;
}

int Pow(int base,int p)
{
	int ret = 1;
	for(;p;p>>=1,base=1ll*base*base%998244353)
		if(p&1)
			ret = ret * 1ll * base % 998244353;
	return ret;
}

void exgcd(int a,int b,int &x,int &y,int &gcd)
{
	if(!b) gcd=a,x=1,y=0;
	else exgcd(b,a%b,y,x,gcd),
		y-=a/b*x;
}

int main()
{
	scanf("%d",&k);
	for(int i=0;i<k;i++) scanf("%d",&b.a[0][i]);
	for(int i=1;i<k;i++) b.a[i][i-1] = 1;
	scanf("%d%d",&n,&m);
	n-=k;
	b = Pow(b,n);
	int tmp = b.a[0][0];
	
	
	int G = 3;
	for(int i=0,s=1;i<S;i++,s=1ll*s*G%998244353) 
		mp[s] = i;
	int Gp = Pow(Pow(G,S),Mod-2);
	int zb = 0;
	for(int i=0,s=m,tmp;i<S;i++,s=1ll*s*Gp%998244353)
		if(mp.count(s))
		{
			zb = mp[s] + i * S;
			break;
		}
	
	int x,y,gcd;
	exgcd(tmp,998244352,x,y,gcd);	
	if(zb % gcd) puts("-1");
	else
	{
		zb /= gcd;
		x = 1ll * x * zb % mod;
		printf("%d\n",Pow(3,(x+mod)%mod));
	}	
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/86739330