題解 小L的數列
阿新 • • 發佈:2021-10-10
重度卡常題,還不給O2
發現看著很像矩陣優化,所以試著放到矩陣上
發現乘法可以轉化為每個底數的冪次的加法,於是可以轉移了
具體地,考慮矩陣乘法的實際意義,可以用初始矩陣的一列來描述一個 \(f_i\)
然後轉移就很好寫了,\(b_{k, j}\) 的實際意義就是一列要乘的係數
複雜度 \(O(k^3logn)\),會被卡成50pts
若是每次轉移 \(k\) 輪而不是1輪就可以到 \(O(k^3log\frac{n}{k})\),就可以過了
Code:
#include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define N 100010 #define ll long long //#define int long long char buf[1<<21], *p1=buf, *p2=buf; #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++) inline int read() { int ans=0, f=1; char c=getchar(); while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();} while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();} return ans*f; } int n, k; ll b[N], f[N]; const ll mod=998244353; const ll mod2=mod-1; const int imod2=mod2; inline void md2(int& a, int b) {a+=b; a=a>=imod2?a-imod2:a;} inline ll qpow(ll a, ll b) {ll ans=1ll; for (; b; b>>=1,a=a*a%mod) if (b&1) ans=ans*a%mod; return ans;} namespace force{ void solve() { for (int i=k+1; i<=n; ++i) { f[i]=1; for (int j=1; j<=k; ++j) { f[i]=f[i]*qpow(f[i-j], b[j])%mod; } } printf("%lld\n", f[n]); exit(0); } } namespace task1{ struct matrix{ int a[205][205], n, m; matrix(){memset(a, 0, sizeof(a));} matrix(int x, int y){n=x; m=y; memset(a, 0, sizeof(a));} inline void resize(int x, int y){n=x; m=y; memset(a, 0, sizeof(a));} void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<a[i][j]<<' '; cout<<endl;} cout<<endl;} inline int* operator [] (int t) {return a[t];} inline matrix operator * (matrix b) { matrix ans(n, b.m); for (int i=1; i<=n; ++i) for (int k=1; k<=m; ++k) if (a[i][k]) for (int j=1; j<=b.m; ++j) md2(ans[i][j], 1ll*a[i][k]*b[k][j]%mod2); return ans; } }mat, t; matrix qpow(matrix a, ll b) {matrix ans=a; --b; for (; b; a=a*a,b>>=1) if (b&1) ans=ans*a; return ans;} inline ll qpow(ll a, ll b) {ll ans=1ll; for (; b; b>>=1,a=a*a%mod) if (b&1) ans=ans*a%mod; return ans;} void solve() { if (n<=k) {printf("%lld\n", f[n]); exit(0);} mat.resize(k, k); t.resize(k, k); for (int i=1; i<=k; ++i) mat[i][i]=1; for (int i=2; i<=k; ++i) t[i][i-1]=1; for (int i=1; i<=k; ++i) t[i][k]=b[k-i+1]; #if 0 cout<<"---mat---"<<endl; mat.put(); cout<<"---t---"<<endl; t.put(); mat=mat*t; cout<<"---ans---"<<endl; mat.put(); #endif t=qpow(t, n-k); // cout<<"---t---"<<endl; // t.put(); mat=mat*t; ll ans=1; // cout<<"---ans---"<<endl; // mat.put(); for (int i=1; i<=k; ++i) ans=ans*qpow(f[i], mat[i][k])%mod; printf("%lld\n", ans); exit(0); } } signed main() { freopen("seq.in", "r", stdin); freopen("seq.out", "w", stdout); n=read(); k=read(); bool all_one=1; for (int i=1; i<=k; ++i) b[i]=read(); for (int i=1; i<=k; ++i) { f[i]=read(); if (f[i]!=1) all_one=0; } // force::solve(); if (all_one) {puts("1"); return 0;} else task1::solve(); return 0; }