[矩阵乘法][快速幂] Jzoj P6275 小L的数列

Description

题解

  • 很容易想到矩阵乘法,然后怎么构建矩阵呢?
  •  a[i][K]=b[i],a[i][i-1]=(i!=1)
  • 然后将每个数独立来看,分别做矩阵乘法就可以拿到k<=30的分,但其实因为矩阵相同,所以可以将矩阵的幂预处理
  • 需要注意矩乘时指数是mod p-1

代码

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #define ll long long
 5 using namespace std;
 6 const ll N=210,mo=998244353;
 7 ll n,k,ans,f[N];
 8 struct node { ll a[N][N]; }A;
 9 node mul(node x,node y)
10 {
11     node c;
12     for(ll i=1;i<=k;i++) for(ll j=1;j<=k;j++) c.a[i][j]=0;
13     for(ll i=1;i<=k;i++) for(ll j=1;j<=k;j++) for(ll p=1;p<=k;p++) (c.a[i][j]+=x.a[i][p]*y.a[p][j]%(mo-1))%=mo-1;
14     return c;
15 }
16 ll Ksm(ll a,ll b) 
17 {
18     if (!b) return 1;
19     if (!a) return 0;
20     b--; ll r=a; 
21     for (;b;b>>=1,a=a*a%mo) if (b&1) r=a*r%mo; return r; 
22 }
23 node ksm(node x,ll y) { y--; node r=x; for (;y;y>>=1,A=mul(A,A)) if (y&1) r=mul(r,A); return r; }
24 int main()
25 {
26     freopen("seq.in","r",stdin),freopen("seq.out","w",stdout),scanf("%lld%lld",&n,&k);
27     for (ll i=2;i<=k;i++) A.a[i][i-1]=1;
28     for (ll i=k;i>=1;i--) scanf("%lld",&A.a[i][k]);
29     for (ll i=1;i<=k;i++) scanf("%lld",&f[i]);
30     if (n<=k) { printf("%lld",f[n]); return 0;}
31     n-=k,A=ksm(A,n),ans=1;
32     for (ll i=1;i<=k;i++) ans=ans*Ksm(f[i],A.a[i][k])%mo;
33     printf("%lld",ans);
34 }

猜你喜欢

转载自www.cnblogs.com/Comfortable/p/11317990.html
今日推荐