[矩阵乘法]JZOJ 6275 小L的数列
分析
N大K小比较显然是矩阵乘法
我们发现最终答案一定可以由原来的f1-fk的幂的乘积构成
那么考虑计算指数,设矩阵A为i-k~i-1的某个f在各个位置上的指数,那么转移矩阵C为
0 0 0 bk
1 0 0 bk-1
0 1 0 bk-2
0 0 1 bk-3
0 0 0 bk-4
看起来时间复杂度是k^4logn的?因为每个初始f都要处理一次,但是不难发现变化的是矩阵A,C是不变的,所以可以预处理出来C后统计答案
减小指数要用费马小定理
#include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; const ll P=998244353; const int N=210; int n,k; struct Rect { ll a[N][N]; void In() { for (int i=1;i<=k;i++) a[i][i]=1; } void Empty() {memset(a,0,sizeof a);} }C,c; Rect operator * (Rect a,Rect b) { c.Empty(); for (int i=1;i<=k;i++) for (int j=1;j<=k;j++) for (int l=1;l<=k;l++) (c.a[i][j]+=a.a[i][l]*b.a[l][j]%(P-1ll))%=(P-1ll); return c; } ll f[N],ans; void Pow(int y) { Rect x=C;C.Empty();C.In(); for (;y;y>>=1) { if (y&1) C=C*x; x=x*x; } } ll Pow1(ll x,ll y) {ll ans=1;for (;y;y>>=1ll,x=x*x%P) if (y&1ll) ans=ans*x%P;return ans;} int main() { freopen("seq.in","r",stdin); freopen("seq.out","w",stdout); scanf("%d%d",&n,&k); for (int i=k;i;i--) scanf("%lld",&C.a[i][k]); for (int i=1;i<=k;i++) scanf("%lld",&f[i]); for (int i=2;i<=k;i++) C.a[i][i-1]=1; if (n<=k) { printf("%lld",f[n]); return 0; } Pow(n-k);ans=1; for (int i=1;i<=k;i++) ans=(ans*Pow1(f[i],C.a[i][k]))%P; printf("%lld",ans); }
在日渐沉没的世界里,我发现了你。