无论是矩阵快速幂求第n项,还是给出输出前几项求规律的第n项,几乎就没有它做不到的
BM推线性递推式,最低阶的复杂度好像是n*n*log(n)。n是输入项数,比高斯消元算快很多。
对于k阶递推式至少要输入2k项才能有足够大参数解出方程系数。
一阶是只这个递推数列只针对前一项有效,例如 a(n+1)=2a(n)。如果是针对前两项,则叫二阶,比如斐波那契数列。
又比如 a(n) = 2*a(n-1) + a(n-2) - 2*a(n-3) - a(n-4), n > 3就是四阶
线性说白了就是一次函数关系。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define pb push_back
typedef long long ll;
#define SZ(x) ((ll)(x).size())
typedef vector<ll> VI;
typedef pair<ll,ll> PII;
const ll mod=998244353;
ll powmod(ll a,ll b) {
ll res=1;
a%=mod;
assert(b>=0);
for(; b; b>>=1) {
if(b&1)res=res*a%mod;
a=a*a%mod;
}
return res;
}
ll _,n;
namespace linear_seq {
const ll N=10010;
ll res[N],base[N],_c[N],_md[N];
vector<ll> Md;
void mul(ll *a,ll *b,ll k) {
rep(i,0,k+k) _c[i]=0;
rep(i,0,k) if (a[i]) rep(j,0,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
for (ll i=k+k-1; i>=k; i--) if (_c[i])
rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
rep(i,0,k) a[i]=_c[i];
}
ll solve(ll n,VI a,VI b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
ll ans=0,pnt=0;
ll k=SZ(a);
assert(SZ(a)==SZ(b));
rep(i,0,k) _md[k-1-i]=-a[i];
_md[k]=1;
Md.clear();
rep(i,0,k) if (_md[i]!=0) Md.push_back(i);
rep(i,0,k) res[i]=base[i]=0;
res[0]=1;
while ((1ll<<pnt)<=n) pnt++;
for (ll p=pnt; p>=0; p--) {
mul(res,res,k);
if ((n>>p)&1) {
for (ll i=k-1; i>=0; i--) res[i+1]=res[i];
res[0]=0;
rep(j,0,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
}
}
rep(i,0,k) ans=(ans+res[i]*b[i])%mod;
if (ans<0) ans+=mod;
return ans;
}
VI BM(VI s) {
VI C(1,1),B(1,1);
ll L=0,m=1,b=1;
rep(n,0,SZ(s)) {
ll d=0;
rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;
if (d==0) ++m;
else if (2*L<=n) {
VI T=C;
ll c=mod-d*powmod(b,mod-2)%mod;
while (SZ(C)<SZ(B)+m) C.pb(0);
rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
L=n+1-L;
B=T;
b=d;
m=1;
} else {
ll c=mod-d*powmod(b,mod-2)%mod;
while (SZ(C)<SZ(B)+m) C.pb(0);
rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
++m;
}
}
return C;
}
ll gao(VI a,ll n) {
VI c=BM(a);
c.erase(c.begin());
rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;
return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
}
};
int main() {
while (~scanf("%lld",&n)) {
vector<ll>v;
v.push_back(0);//前几项
v.push_back(1);
v.push_back(2);
v.push_back(5);
v.push_back(10);
v.push_back(20);
v.push_back(38);
v.push_back(71);
v.push_back(130);
v.push_back(235);
v.push_back(420);
v.push_back(744);
v.push_back(1308);
//输入n ,输出第n项的值
printf("%lld\n",linear_seq::gao(v,n-1));
}
}